delaunay mapgen 1st version
This commit is contained in:
@ -8,6 +8,11 @@ const MobComponent = "mob"
|
||||
const MoveableComponent = "movable"
|
||||
const CarriedComponent = "carried"
|
||||
const UsableComponent = "usable"
|
||||
const WearableComponent = "usable"
|
||||
const ArmsComponent = "arms"
|
||||
const RangedComponent = "ranged"
|
||||
const AmmoComponent = "ammo"
|
||||
const ArmorComponent = "armor"
|
||||
|
||||
type Component interface {
|
||||
Type() string
|
||||
|
@ -167,7 +167,7 @@ func (ps *precomputedShade) PrecomputeFovMap() {
|
||||
//Bresanham lines / Raycast
|
||||
var lineX, lineY float64
|
||||
for i := 0; i < 720; i++ { // 1/2 of angles
|
||||
dx := math.Sin(float64(i) / (float64(360) / math.Pi)) //1/2 of angles
|
||||
dx := math.Sin(float64(i) / (float64(360) / math.Pi)) //1/2 of angle
|
||||
dy := math.Cos(float64(i) / (float64(360) / math.Pi))
|
||||
|
||||
lineX = 0
|
||||
|
@ -1,4 +1,4 @@
|
||||
package mapgens
|
||||
package _default
|
||||
|
||||
import (
|
||||
"fmt"
|
196
engine/gamemap/mapgens/delaunaymst/delaunay_mst.go
Normal file
196
engine/gamemap/mapgens/delaunaymst/delaunay_mst.go
Normal file
@ -0,0 +1,196 @@
|
||||
package delaunaymst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||
"lab.zaar.be/thefish/alchemyst-go/util"
|
||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||
"lab.zaar.be/thefish/alchemyst-go/util/delaunay"
|
||||
)
|
||||
|
||||
//fixme move to config
|
||||
var minRoomSize = 5
|
||||
var maxRoomSize = 15
|
||||
var maxrooms = 59
|
||||
|
||||
var fges = map[int]types.RectFill{
|
||||
1: types.RectFill{
|
||||
Top: func() *gamemap.Tile { return gamemap.NewWall() },
|
||||
Bottom: func() *gamemap.Tile { return gamemap.NewWall() },
|
||||
Left: func() *gamemap.Tile { return gamemap.NewWall() },
|
||||
Right: func() *gamemap.Tile { return gamemap.NewWall() },
|
||||
BottomLeft: func() *gamemap.Tile { return gamemap.NewWall() },
|
||||
BottomRight: func() *gamemap.Tile { return gamemap.NewWall() },
|
||||
TopLeft: func() *gamemap.Tile { return gamemap.NewWall() },
|
||||
TopRight: func() *gamemap.Tile { return gamemap.NewWall() },
|
||||
Body: func() *gamemap.Tile { return gamemap.NewFloor() },
|
||||
},
|
||||
|
||||
2: types.RectFill{
|
||||
Top: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
||||
Bottom: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
||||
Left: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
||||
Right: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
||||
BottomLeft: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
||||
BottomRight: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
||||
TopLeft: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
||||
TopRight: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
||||
Body: func() *gamemap.Tile { return gamemap.NewDeepWaterTile() },
|
||||
},
|
||||
}
|
||||
|
||||
func DelaunayMstGen(ctx appctx.ClientCtx, l *gamemap.Level) (*gamemap.Level, []gamemap.Room) {
|
||||
rng := util.NewRNG()
|
||||
//load prefabs
|
||||
pfLoader := gamemap.NewPrefabLoader(ctx)
|
||||
pfRooms := pfLoader.PrefabRoomsList()
|
||||
|
||||
//fill with walls
|
||||
for i := 0; i < l.W; i ++ {
|
||||
for j := 0; j < l.H; j++ {
|
||||
l.SetTileByXY(i, j, gamemap.NewWall())
|
||||
}
|
||||
}
|
||||
rooms := make([]gamemap.Room, 0)
|
||||
prefabUsed := false
|
||||
for i := 0; i < maxrooms; i++ {
|
||||
failed := false
|
||||
var fillage types.RectFill
|
||||
fillage = fges[rng.GetWeightedEntity(map[int]int{1: 10, 2: 1})]
|
||||
var newRoom gamemap.Room
|
||||
if !prefabUsed || rng.Range(0, 5) > 3 {
|
||||
//prefab
|
||||
prefabUsed = true
|
||||
r := pfRooms[rng.Range(0, len(pfRooms))] //copy to local scope
|
||||
newRoom = r
|
||||
} else {
|
||||
newRoom = gamemap.NewRandomRectRoom(
|
||||
rng,
|
||||
rng.Range(minRoomSize, maxRoomSize),
|
||||
rng.Range(minRoomSize, maxRoomSize),
|
||||
fillage,
|
||||
)
|
||||
}
|
||||
where := types.Coords{
|
||||
rng.Range(1, l.W-2-newRoom.W),
|
||||
rng.Range(1, l.H-2-newRoom.H),
|
||||
}
|
||||
|
||||
newRoom.MoveToCoords(where)
|
||||
|
||||
for _, otherRoom := range rooms {
|
||||
if otherRoom.Intersects(newRoom.Rect) {
|
||||
failed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if failed {
|
||||
continue
|
||||
}
|
||||
if len(newRoom.Connectors) > 0 {
|
||||
rooms = append(rooms, newRoom)
|
||||
}
|
||||
}
|
||||
|
||||
for _, room := range rooms {
|
||||
err := room.BlitToLevel(l)
|
||||
if err != nil {
|
||||
fmt.Printf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
centers := make([]types.Coords, 0)
|
||||
for _, room := range rooms {
|
||||
centers = append(centers, room.Center)
|
||||
}
|
||||
|
||||
for _, edge := range delaunay.GetMst(centers, l.W, l.H) {
|
||||
MedianStraight(rng, l, rooms, centers, edge)
|
||||
}
|
||||
|
||||
return l, rooms
|
||||
}
|
||||
|
||||
func MedianStraight(rng *util.RNG, l *gamemap.Level, rooms []gamemap.Room, centers []types.Coords, edge types.Edge) {
|
||||
//find connected rooms
|
||||
var fromRoom, toRoom gamemap.Room
|
||||
for _, room := range rooms {
|
||||
if room.Center == edge.From {
|
||||
fromRoom = room
|
||||
continue
|
||||
}
|
||||
if room.Center == edge.To {
|
||||
toRoom = room
|
||||
continue
|
||||
}
|
||||
if len(fromRoom.Connectors) > 0 && len(toRoom.Connectors) > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
midpoint := edge.Midpoint()
|
||||
fromConnector := findNearestCoonector(midpoint, fromRoom)
|
||||
toConnector := findNearestCoonector(midpoint, toRoom)
|
||||
connectStraight(rng, l, fromConnector, toConnector, midpoint)
|
||||
}
|
||||
|
||||
func findNearestCoonector(midpoint types.Coords, room gamemap.Room) types.Coords {
|
||||
var nearest types.Coords
|
||||
for _, con := range room.Connectors {
|
||||
if nearest.X == 0 {
|
||||
nearest = con
|
||||
continue
|
||||
}
|
||||
if midpoint.DistanceTo(con) < midpoint.DistanceTo(nearest) {
|
||||
nearest = con
|
||||
}
|
||||
}
|
||||
return nearest
|
||||
}
|
||||
|
||||
func connectStraight(rng *util.RNG, l *gamemap.Level, from, to, midpoint types.Coords) {
|
||||
toss := rng.Range(0, 1)
|
||||
if toss == 0 {
|
||||
digHTunnel(l, from.X, midpoint.X, from.Y)
|
||||
digVTunnel(l, from.Y, to.Y, midpoint.X)
|
||||
digHTunnel(l, midpoint.X, to.X, to.Y)
|
||||
} else {
|
||||
digVTunnel(l, from.Y, midpoint.Y, from.X)
|
||||
digHTunnel(l, from.X, to.X, midpoint.Y)
|
||||
digVTunnel(l, midpoint.Y, to.Y, to.X)
|
||||
}
|
||||
}
|
||||
|
||||
func digHTunnel(l *gamemap.Level, x1, x2, y int) {
|
||||
var start, finish int
|
||||
if x1 < x2 {
|
||||
start = x1
|
||||
finish = x2
|
||||
} else {
|
||||
start = x2
|
||||
finish = x1
|
||||
}
|
||||
for i := start; i <= finish; i++ {
|
||||
if l.InBounds(types.Coords{i, y}) {
|
||||
l.SetTileByXY(i, y, gamemap.NewFloor())
|
||||
//l.Tiles[i][y] = gamemap.NewFloor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func digVTunnel(l *gamemap.Level, y1, y2, x int) {
|
||||
var start, finish int
|
||||
if y1 < y2 {
|
||||
start = y1
|
||||
finish = y2
|
||||
} else {
|
||||
start = y2
|
||||
finish = y1
|
||||
}
|
||||
for i := start; i <= finish; i++ {
|
||||
if l.InBounds(types.Coords{x, i}) {
|
||||
l.SetTileByXY(x, i, gamemap.NewFloor())
|
||||
}
|
||||
}
|
||||
}
|
@ -57,11 +57,12 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//prepare actual legends
|
||||
currentTileLegend := file.DefaultTileLegend
|
||||
currentMobsLegend := file.DefaultMobsLegend
|
||||
currentItemLegend := file.DefaultItemLegend
|
||||
|
||||
for _, rawPrefab := range file.Prefabs {
|
||||
//prepare actual legends
|
||||
currentTileLegend := file.DefaultTileLegend
|
||||
currentMobsLegend := file.DefaultMobsLegend
|
||||
currentItemLegend := file.DefaultItemLegend
|
||||
|
||||
for k,v := range rawPrefab.TileLegend {
|
||||
currentTileLegend[k] = v
|
||||
@ -99,7 +100,7 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
|
||||
continue
|
||||
}
|
||||
if shortName == "connector" {
|
||||
f = NewFloor
|
||||
f = NewWall
|
||||
room.Connectors = append(room.Connectors, types.Coords{i,j})
|
||||
} else {
|
||||
f, ok = TileTypeMap[shortName]
|
||||
@ -122,4 +123,4 @@ var TileTypeMap = map[string]func()*Tile{
|
||||
"decorated_wall": NewDecoratedWall,
|
||||
"water": NewWaterTile,
|
||||
"deep_water": NewDeepWaterTile,
|
||||
}
|
||||
}
|
||||
|
14
engine/items/ammo.go
Normal file
14
engine/items/ammo.go
Normal file
@ -0,0 +1,14 @@
|
||||
package items
|
||||
|
||||
import (
|
||||
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||
"lab.zaar.be/thefish/alchemyst-go/engine/items/itemprops"
|
||||
)
|
||||
|
||||
type Ammo struct {
|
||||
itemprops.DamageProfile
|
||||
}
|
||||
|
||||
func (a *Ammo) Type() string {
|
||||
return ecs.AmmoComponent
|
||||
}
|
11
engine/items/armor.go
Normal file
11
engine/items/armor.go
Normal file
@ -0,0 +1,11 @@
|
||||
package items
|
||||
|
||||
import "lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||
|
||||
type Armor struct {
|
||||
DefenceProfile struct{}
|
||||
}
|
||||
|
||||
func (a *Armor) Type() string {
|
||||
return ecs.ArmorComponent
|
||||
}
|
14
engine/items/arms.go
Normal file
14
engine/items/arms.go
Normal file
@ -0,0 +1,14 @@
|
||||
package items
|
||||
|
||||
import (
|
||||
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||
"lab.zaar.be/thefish/alchemyst-go/engine/items/itemprops"
|
||||
)
|
||||
|
||||
type Arms struct {
|
||||
itemprops.DamageProfile
|
||||
}
|
||||
|
||||
func (a Arms) Type() string {
|
||||
return ecs.ArmsComponent
|
||||
}
|
@ -2,8 +2,26 @@ package items
|
||||
|
||||
import "lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||
|
||||
type Carried struct {}
|
||||
type CarriedFace interface {
|
||||
Drop()
|
||||
Pickup()
|
||||
}
|
||||
|
||||
type Carried struct {
|
||||
Mass int //масса в граммах
|
||||
Bulk int //внешний размер, см3
|
||||
}
|
||||
|
||||
func (c *Carried) Type() string {
|
||||
return ecs.CarriedComponent
|
||||
}
|
||||
|
||||
func (c *Carried) Pickup() {}
|
||||
func (c *Carried) Drop() {}
|
||||
|
||||
func (c *Carried) GetMass() int {
|
||||
return c.Mass
|
||||
}
|
||||
func (c *Carried) GetBulk() int {
|
||||
return c.Bulk
|
||||
}
|
7
engine/items/itemprops/damage.go
Normal file
7
engine/items/itemprops/damage.go
Normal file
@ -0,0 +1,7 @@
|
||||
package itemprops
|
||||
|
||||
type DamageProfile struct {
|
||||
Pierce int
|
||||
Bash int
|
||||
Cleave int
|
||||
}
|
11
engine/items/ranged.go
Normal file
11
engine/items/ranged.go
Normal file
@ -0,0 +1,11 @@
|
||||
package items
|
||||
|
||||
import "lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||
|
||||
type Ranged struct {
|
||||
RangeProfile struct{} //это зависимость дальности-скорости от характеристик и атрибутов
|
||||
}
|
||||
|
||||
func (r *Ranged) Type() string {
|
||||
return ecs.RangedComponent
|
||||
}
|
@ -2,9 +2,16 @@ package items
|
||||
|
||||
import "lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||
|
||||
type Useable struct {}
|
||||
type UsableFace interface {
|
||||
Use()
|
||||
}
|
||||
|
||||
type Usable struct {}
|
||||
|
||||
|
||||
func (u *Useable) Type() string {
|
||||
func (u *Usable) Type() string {
|
||||
return ecs.UsableComponent
|
||||
}
|
||||
|
||||
func (u *Usable) Use() {
|
||||
}
|
16
engine/items/wearable.go
Normal file
16
engine/items/wearable.go
Normal file
@ -0,0 +1,16 @@
|
||||
package items
|
||||
|
||||
import "lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||
|
||||
type WearableFace interface {
|
||||
Wear()
|
||||
Takeoff()
|
||||
}
|
||||
|
||||
type Wearable struct {
|
||||
Bodypart int //куда собстно одевать
|
||||
}
|
||||
|
||||
func (w *Wearable) Type() string {
|
||||
return ecs.WearableComponent
|
||||
}
|
82
engine/matertals/properties.go
Normal file
82
engine/matertals/properties.go
Normal file
@ -0,0 +1,82 @@
|
||||
package matertals
|
||||
|
||||
import "github.com/rs/zerolog/log"
|
||||
|
||||
type MaterialProperties struct {
|
||||
Density float64 //Плотность (кг / м3)
|
||||
Tougnness float64 //Ударная вязкость, мера скорости поглощения энергии без деформаций, джоули на квадратный метр в секунду
|
||||
Brittleness float64 //Хрупкость - обратная пластичности (в основном за счет внешних эффектов), джоули на квадртаный метр, после которых раскол
|
||||
MeltingPoint float64 //точка перехода из твердого в жидкое, градусы Цельсия при нормальном давлении
|
||||
BoilingPoint float64 //точка кипения - из жидкого в газ, градусы Цельсия при нормальном давлении
|
||||
Conductivity bool //проводимость эл. тока
|
||||
}
|
||||
|
||||
//агрегатное состояние
|
||||
type MatterState int
|
||||
|
||||
const (
|
||||
Solid MatterState = iota //кристаллическая решетка
|
||||
Liquid
|
||||
Gas
|
||||
Plasma
|
||||
|
||||
Glass //нет кристаллической решетки, аморфный
|
||||
)
|
||||
|
||||
var transitions = map[MatterState][]MatterState{
|
||||
Solid: {Liquid, Gas},
|
||||
Liquid: {Solid, Gas, Glass},
|
||||
Gas: {Solid, Plasma},
|
||||
Plasma: {Gas},
|
||||
|
||||
Glass: {Liquid},
|
||||
|
||||
}
|
||||
|
||||
func (ms MatterState) Change(from MatterState, to MatterState) bool {
|
||||
if from == to {
|
||||
return true
|
||||
}
|
||||
|
||||
_, ok := transitions[from]
|
||||
|
||||
if ok {
|
||||
newStateFound := func(lst []MatterState, to MatterState) bool {
|
||||
for _, b := range lst {
|
||||
if b == to {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}(transitions[from], to)
|
||||
if !newStateFound {
|
||||
log.Warn().Msgf("Transition %s -> %s is impossible", from, to)
|
||||
return false
|
||||
}
|
||||
// check temperatures/conditions, see template
|
||||
/*
|
||||
Solid -> Gas Sublimation
|
||||
Solid -> Liquid Melting
|
||||
|
||||
Liquid -> Gas Boiling
|
||||
Liquid -> Solid Freezing
|
||||
|
||||
Gas -> Solid Deposition
|
||||
Gas -> Liquid Condensation
|
||||
|
||||
Gas -> Plasma Ionization
|
||||
Plasma -> Gas Recombination
|
||||
*/
|
||||
}
|
||||
|
||||
//При фазовом переходе первого рода скачкообразно изменяются самые главные, первичные экстенсивные параметры:
|
||||
// удельный объём,
|
||||
// количество запасённой внутренней энергии,
|
||||
// концентрация компонентов и т. п.
|
||||
//
|
||||
// Фазовые переходы второго рода происходят в тех случаях, когда меняется симметрия строения вещества
|
||||
// (симметрия может полностью исчезнуть или понизиться).
|
||||
|
||||
return true
|
||||
|
||||
}
|
@ -101,7 +101,7 @@ func (devm *DevmenuScreen) Render() {
|
||||
menuLayer.WithColor(devm.fgColor).PrintInside(
|
||||
devm.Rect,
|
||||
strings.Join([]string{
|
||||
"Dev Menu:",
|
||||
"Действия для разработчика:",
|
||||
"[color=green]v[/color] - set all tiles visible",
|
||||
"[color=green]i[/color] - set all tiles invisible",
|
||||
fmt.Sprintf("[color=green]p[/color] - toggle passwall: %v",
|
||||
|
@ -4,3 +4,23 @@ type Edge struct {
|
||||
From Coords
|
||||
To Coords
|
||||
}
|
||||
|
||||
func (e *Edge) Midpoint() Coords {
|
||||
var dx, dy, minX, minY int
|
||||
if e.From.X > e.To.X {
|
||||
minX = e.To.X
|
||||
dx = e.From.X - e.To.X
|
||||
} else {
|
||||
minX = e.From.X
|
||||
dx = e.To.X - e.From.X
|
||||
}
|
||||
|
||||
if e.From.Y > e.To.Y {
|
||||
minY = e.To.Y
|
||||
dy = e.From.Y - e.To.Y
|
||||
} else {
|
||||
minY = e.From.Y
|
||||
dy = e.To.Y - e.From.Y
|
||||
}
|
||||
return Coords{minX + dx / 2, minY + dy / 2}
|
||||
}
|
Reference in New Issue
Block a user