Compare commits
16 Commits
20ba03c758
...
4913b0a567
Author | SHA1 | Date | |
---|---|---|---|
4913b0a567 | |||
dc2e6ea2b5 | |||
5613744d6e | |||
4c0117b6a7 | |||
|
4f18b6db18 | ||
|
f52e235799 | ||
def43265de | |||
09bfa44c78 | |||
|
31d5be5d07 | ||
|
3886a05ce2 | ||
d9a8529a20 | |||
76780d7936 | |||
9f3eaafa3f | |||
d2b22f4760 | |||
|
2352ec4f0a | ||
|
e738568c14 |
18
TODO
18
TODO
@ -27,7 +27,7 @@ Assets and i18n:
|
|||||||
ECS & engine:
|
ECS & engine:
|
||||||
- implement time queue (how to deal with closures?) (?) github.com/thefish/scheduleq - get rid od time.Now inside
|
- implement time queue (how to deal with closures?) (?) github.com/thefish/scheduleq - get rid od time.Now inside
|
||||||
- move all rendering to systems
|
- move all rendering to systems
|
||||||
- try to move input handling to systems
|
+ try to move input handling to systems
|
||||||
|
|
||||||
Dungeon and branches:
|
Dungeon and branches:
|
||||||
General:
|
General:
|
||||||
@ -53,7 +53,7 @@ Combat:
|
|||||||
- mass
|
- mass
|
||||||
- damage calculated from:
|
- damage calculated from:
|
||||||
kinetic energy is calculated by mass / speed / material density (p = mv) масса на скорость = кинетическая энергия
|
kinetic energy is calculated by mass / speed / material density (p = mv) масса на скорость = кинетическая энергия
|
||||||
next you determine target and its subpart (accuracy appied)
|
next you determine target and its subpart (accuracy applied)
|
||||||
next we calculate the area, on which kinetic energy is applied (determined by piercing, hacking, crushing damage profile) находим площадь
|
next we calculate the area, on which kinetic energy is applied (determined by piercing, hacking, crushing damage profile) находим площадь
|
||||||
next we calculate
|
next we calculate
|
||||||
|
|
||||||
@ -81,5 +81,17 @@ Combat:
|
|||||||
|
|
||||||
Quest engine:
|
Quest engine:
|
||||||
- look at parsers like URQL etc
|
- look at parsers like URQL etc
|
||||||
- distorted Aschenputtel story / partisans / rapist prince / Grey Mountains
|
- distorted Aschenputtel story / partisans / rapist prince / Grey Mountains / No gold
|
||||||
|
|
||||||
|
|
||||||
|
No Gold in Gery Mountains / Kim Newman
|
||||||
|
|
||||||
|
- Drakenfells castle //location
|
||||||
|
- Greteschele // char / rogue / charred zombie
|
||||||
|
- Yom Lamprecht // char / rogue /
|
||||||
|
- Tiley manor(?) // location / княжество
|
||||||
|
- Melissa d'Acu // char / small girl
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
26
assets/materials/commons.json
Normal file
26
assets/materials/commons.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"material_flags": [
|
||||||
|
{
|
||||||
|
"metal": {
|
||||||
|
"conducts_elictricity": true,
|
||||||
|
"blocks_liquid": true,
|
||||||
|
"acid_resistant": true,
|
||||||
|
"blocks_gas": true,
|
||||||
|
"flammable": false,
|
||||||
|
"conducts_heat": true,
|
||||||
|
"radiates": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wood": {
|
||||||
|
"conducts_elictricity": false,
|
||||||
|
"blocks_liquid": true,
|
||||||
|
"acid_resistant": false,
|
||||||
|
"blocks_gas": true,
|
||||||
|
"flammable": true,
|
||||||
|
"conducts_heat": false,
|
||||||
|
"radiates": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
28
assets/materials/metals/metals.json
Normal file
28
assets/materials/metals/metals.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"materials": [
|
||||||
|
{
|
||||||
|
"steel": {
|
||||||
|
"name": "steel",
|
||||||
|
"material_flags": {
|
||||||
|
"$ref": "#/material_flags/metal"
|
||||||
|
},
|
||||||
|
"density": "7800",
|
||||||
|
"fracture_toughness": "30",
|
||||||
|
"melting_point": "1400",
|
||||||
|
"boiling_point": "3200"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iron": {
|
||||||
|
"name": "iron",
|
||||||
|
"material_flags": {
|
||||||
|
"$ref": "#/material_flags/metal"
|
||||||
|
},
|
||||||
|
"density": "7800",
|
||||||
|
"fracture_toughness": "12",
|
||||||
|
"melting_point": "1400",
|
||||||
|
"boiling_point": "3200"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
15
assets/materials/misc.json
Normal file
15
assets/materials/misc.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"material_flags": [
|
||||||
|
{
|
||||||
|
"acme-fiber": {
|
||||||
|
"conducts_elictricity": false,
|
||||||
|
"blocks_liquid": true,
|
||||||
|
"acid_resistant": true,
|
||||||
|
"blocks_gas": true,
|
||||||
|
"flammable": false,
|
||||||
|
"conducts_heat": false,
|
||||||
|
"radiates": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
16
assets/materials/wood/wood.json
Normal file
16
assets/materials/wood/wood.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"materials": [
|
||||||
|
{
|
||||||
|
"oakwood": {
|
||||||
|
"name": "testoakwood",
|
||||||
|
"material_flags": {
|
||||||
|
"$ref": "#/material_flags/wood"
|
||||||
|
},
|
||||||
|
"density": "700",
|
||||||
|
"fracture_toughness": "4.5",
|
||||||
|
"melting_point": "600",
|
||||||
|
"boiling_point": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
460
cmd/game/main.go
460
cmd/game/main.go
@ -1,26 +1,26 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap/mapgens"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap/mapgens"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/items"
|
"lab.zaar.be/thefish/alchemyst-go/engine/items"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/mob/movement"
|
"lab.zaar.be/thefish/alchemyst-go/engine/mob/movement"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/screens"
|
"lab.zaar.be/thefish/alchemyst-go/engine/screens"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/ui"
|
"lab.zaar.be/thefish/alchemyst-go/ui"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
|
"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util"
|
"lab.zaar.be/thefish/alchemyst-go/util"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||||
blt "lab.zaar.be/thefish/bearlibterminal"
|
blt "lab.zaar.be/thefish/bearlibterminal"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var modifiers = []int{blt.TK_SHIFT, blt.TK_ALT, blt.TK_CONTROL}
|
var modifiers = []int{blt.TK_SHIFT, blt.TK_ALT, blt.TK_CONTROL}
|
||||||
@ -28,12 +28,12 @@ var modifiers = []int{blt.TK_SHIFT, blt.TK_ALT, blt.TK_CONTROL}
|
|||||||
// Рецепт чтобы убежать от [fatal] 'refresh' was not called from the main thread
|
// Рецепт чтобы убежать от [fatal] 'refresh' was not called from the main thread
|
||||||
// https://github.com/golang/go/wiki/LockOSThread
|
// https://github.com/golang/go/wiki/LockOSThread
|
||||||
func init() {
|
func init() {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
}
|
}
|
||||||
|
|
||||||
//we can run logic in separate goroutines
|
//we can run logic in separate goroutines
|
||||||
//
|
//
|
||||||
// go doSometing(State,...)
|
// go doSomething(State,...)
|
||||||
//
|
//
|
||||||
//and there we go like this:
|
//and there we go like this:
|
||||||
// func doSomething(State main.GameState, args...) {
|
// func doSomething(State main.GameState, args...) {
|
||||||
@ -45,252 +45,254 @@ func init() {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
var State = gamestate.GameState{
|
var State = gamestate.GameState{
|
||||||
Mainfunc: make(chan func()),
|
Mainfunc: make(chan func()),
|
||||||
Exit: make(chan struct{}, 1),
|
Exit: make(chan struct{}, 1),
|
||||||
Input: make(chan string, 1),
|
Input: make(chan string, 1),
|
||||||
RawInput: make(chan int, 1),
|
RawInput: make(chan int, 1),
|
||||||
FovRecompute: make(chan struct{}, 1),
|
FovRecompute: make(chan struct{}, 1),
|
||||||
Redraw: make(chan struct{}, 1),
|
Redraw: make(chan struct{}, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
config := util.LoadConfig()
|
config := util.LoadConfig()
|
||||||
var logLevels = map[string]zerolog.Level{"debug": zerolog.DebugLevel, "info": zerolog.InfoLevel, "warn": zerolog.WarnLevel}
|
var logLevels = map[string]zerolog.Level{"debug": zerolog.DebugLevel, "info": zerolog.InfoLevel, "warn": zerolog.WarnLevel}
|
||||||
var logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}).Level(logLevels[config.Verbosity])
|
var logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}).Level(logLevels[config.Verbosity])
|
||||||
|
|
||||||
// set up context
|
// set up context
|
||||||
mainCtx := appctx.NewClientContext(config, &logger)
|
appctx.NewClientContext(config, &logger)
|
||||||
|
mainCtx := appctx.ClientState
|
||||||
|
|
||||||
//set up main window
|
//set up main window
|
||||||
mw := mainwindow.Init(mainCtx)
|
mw := mainwindow.Init(mainCtx)
|
||||||
defer mw.Close()
|
defer mw.Close()
|
||||||
|
|
||||||
setupLayers(mw)
|
setupLayers(mw)
|
||||||
|
|
||||||
//set up input decoder
|
//set up input decoder
|
||||||
go decodeInput(mainCtx, mw.GetLayer("base"))
|
go decodeInput(mainCtx, mw.GetLayer("base"))
|
||||||
|
|
||||||
//fixme set up (load / generate) level - move to game / enter or title / exit
|
//fixme set up (load / generate) level - move to game / enter or title / exit
|
||||||
//level, rooms := _default.DefaultGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
level, rooms := mapgens.DefaultGen(gamemap.NewLevel("test", 1))
|
||||||
//level, rooms := mapgens.DelaunayMstGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
//level, rooms := mapgens.DelaunayMstGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
||||||
level, rooms := mapgens.DelaunayMstExtGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
//level, rooms := mapgens.DelaunayMstExtGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
||||||
//level, rooms := mapgens.DelaunayPureGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
//level, rooms := mapgens.DelaunayPureGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
||||||
State.Level = level
|
State.Level = level
|
||||||
|
|
||||||
sidebarWidth := 0
|
sidebarWidth := 0
|
||||||
|
|
||||||
//Set up viewport
|
//Set up viewport
|
||||||
vp := mainwindow.NewViewPort(sidebarWidth, 0, (mw.W - sidebarWidth), (mw.H - 0))
|
vp := mainwindow.NewViewPort(sidebarWidth, 0, (mw.W - sidebarWidth), (mw.H - 0))
|
||||||
|
|
||||||
//set up controller
|
//set up controller
|
||||||
|
|
||||||
controller := ecs.NewController(mainCtx)
|
controller := ecs.NewController()
|
||||||
|
|
||||||
controller.MapComponentClass(ecs.CoordsComponent, types.Coords{})
|
controller.MapComponentClass(ecs.CoordsComponent, types.Coords{})
|
||||||
controller.MapComponentClass(ecs.AppearanceComponent, types.Appearance{})
|
controller.MapComponentClass(ecs.AppearanceComponent, types.Appearance{})
|
||||||
controller.MapComponentClass(ecs.MobComponent, mob.Mob{})
|
controller.MapComponentClass(ecs.MobComponent, mob.Mob{})
|
||||||
controller.MapComponentClass(ecs.MoveableComponent, movement.Moveable{})
|
controller.MapComponentClass(ecs.MoveableComponent, movement.Moveable{})
|
||||||
controller.MapComponentClass(ecs.CarriedComponent, movement.Moveable{})
|
controller.MapComponentClass(ecs.CarriedComponent, movement.Moveable{})
|
||||||
controller.MapComponentClass(ecs.UsableComponent, movement.Moveable{})
|
controller.MapComponentClass(ecs.UsableComponent, movement.Moveable{})
|
||||||
controller.MapComponentClass(ecs.BackpackComponent, items.Backpack{})
|
controller.MapComponentClass(ecs.BackpackComponent, items.Backpack{})
|
||||||
|
|
||||||
moveable := movement.Moveable{
|
moveable := movement.Moveable{
|
||||||
Controller: controller,
|
Controller: controller,
|
||||||
Level: level,
|
Level: level,
|
||||||
}
|
}
|
||||||
|
|
||||||
items.Init(controller)
|
items.Init(controller)
|
||||||
|
|
||||||
bp := items.Backpack{MaxMass: 100, MaxBulk: 100}
|
bp := items.Backpack{MaxMass:100, MaxBulk:100}
|
||||||
|
|
||||||
//Set up Screen Manager
|
//Set up Screen Manager
|
||||||
screenMgr := types.NewScreenManager(mainCtx)
|
screenMgr := types.NewScreenManager()
|
||||||
screenMgr.AddScreen("title", screens.NewTitleScreen(mw, screenMgr))
|
screenMgr.AddScreen("title", screens.NewTitleScreen(mw, screenMgr))
|
||||||
screenMgr.AddScreen("game", screens.NewGameScreen(mainCtx, mw, &State, vp, controller, screenMgr))
|
screenMgr.AddScreen("game", screens.NewGameScreen(mw, &State, vp, controller, screenMgr))
|
||||||
screenMgr.AddScreen("help", screens.NewMenuScreen(
|
screenMgr.AddScreen("help", screens.NewMenuScreen(
|
||||||
mw,
|
mw,
|
||||||
screenMgr,
|
screenMgr,
|
||||||
"Help",
|
"Help",
|
||||||
"Keybindings:",
|
"Keybindings:",
|
||||||
//"[color=yellow]Note[/color]: Many of these are not implemented yet",
|
//"[color=yellow]Note[/color]: Many of these are not implemented yet",
|
||||||
"[color=yellow]Note[/color]: Many of these are not implemented yet",
|
"[color=yellow]Note[/color]: Many of these are not implemented yet",
|
||||||
types.NewCenteredRect(mw.Rect, 50, 15),
|
types.NewCenteredRect(mw.Rect, 50, 15),
|
||||||
true).
|
true, ).
|
||||||
SetBgColor("#ef1d494f").
|
SetBgColor("#ef1d494f").
|
||||||
SetFgColor("white").
|
SetFgColor("white").
|
||||||
SetItems([]interface{}{
|
SetItems([]interface{}{
|
||||||
"hjklyubn, NumPad 12346789, arrow keys - move",
|
"hjklyubn, NumPad 12346789, arrow keys - move",
|
||||||
"s or . - pass turn",
|
"s or . - pass turn",
|
||||||
"g or , - pick up item",
|
"g or , - pick up item",
|
||||||
"i - inventory",
|
"i - inventory",
|
||||||
"? - this screen",
|
"? - this screen",
|
||||||
"Ctrl+q - exit",
|
"Ctrl+q - exit",
|
||||||
"f or F - fire or throw weapon",
|
"f or F - fire weapon or throw item",
|
||||||
"z or Z - cast a spell",
|
"z or Z - cast a spell",
|
||||||
"p - pray",
|
"p - pray",
|
||||||
"Ctrl+p - message log",
|
"Ctrl+p - message log",
|
||||||
}).MakeList(),
|
}).MakeList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
inv := screens.InventoryScreen{
|
inv := screens.InventoryScreen{
|
||||||
MenuScreen: screens.NewMenuScreen(
|
MenuScreen: screens.NewMenuScreen(
|
||||||
mw,
|
mw,
|
||||||
screenMgr,
|
screenMgr,
|
||||||
"Inventory",
|
"Inventory",
|
||||||
"Items in your backpack:",
|
"Items in your backpack:",
|
||||||
//"[color=yellow]Note[/color]: Many of these are not implemented yet",
|
//"[color=yellow]Note[/color]: Many of these are not implemented yet",
|
||||||
"",
|
"",
|
||||||
types.NewCenteredRect(mw.Rect, 70, 25),
|
types.NewCenteredRect(mw.Rect, 70, 25),
|
||||||
true).
|
true, ).
|
||||||
SetBgColor("#ef305c70").
|
SetBgColor("#ef305c70").
|
||||||
SetFgColor("white"),
|
SetFgColor("white"),
|
||||||
}
|
}
|
||||||
|
|
||||||
screenMgr.AddScreen("devmenu", screens.NewDevmenuScreen(
|
screenMgr.AddScreen("devmenu", screens.NewDevmenuScreen(
|
||||||
mainCtx,
|
mainCtx,
|
||||||
mw,
|
mw,
|
||||||
controller,
|
controller,
|
||||||
screenMgr,
|
screenMgr,
|
||||||
&State,
|
&State,
|
||||||
types.NewCenteredRect(mw.Rect, 70, 25),
|
types.NewCenteredRect(mw.Rect, 70, 25),
|
||||||
true,
|
true,
|
||||||
).SetBgColor("#ef6d559d").
|
).SetBgColor("#ef6d559d").
|
||||||
SetFgColor("white"),
|
SetFgColor("white"),
|
||||||
)
|
)
|
||||||
|
|
||||||
screenMgr.SetScreenByName("title")
|
screenMgr.SetScreenByName("title")
|
||||||
|
|
||||||
//fixme set up (load / generate) player - move to game / enter or title / exit
|
//fixme set up (load / generate) player - move to game / enter or title / exit
|
||||||
player := controller.CreateEntity([]ecs.Component{})
|
player := controller.CreateEntity([]ecs.Component{})
|
||||||
|
|
||||||
controller.AddComponent(player, types.Appearance{
|
controller.AddComponent(player, types.Appearance{
|
||||||
Glyph: types.PlainGlyphHolder{"@"},
|
Glyph: types.PlainGlyphHolder{"@"},
|
||||||
ColorSet: types.TileColorSet{
|
ColorSet: types.TileColorSet{
|
||||||
Fg: types.PlainColorHolder{255, 255, 255, 255},
|
Fg: types.PlainColorHolder{255, 255, 255, 255},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
controller.AddComponent(player, rooms[0].Center) //implicit Coords
|
controller.AddComponent(player, rooms[0].Center) //implicit Coords
|
||||||
controller.AddComponent(player, moveable)
|
controller.AddComponent(player, moveable)
|
||||||
controller.AddComponent(player, bp)
|
controller.AddComponent(player, bp)
|
||||||
|
|
||||||
//fixme adding items
|
//fixme adding items
|
||||||
potion := controller.CreateEntity([]ecs.Component{})
|
potion := controller.CreateEntity([]ecs.Component{})
|
||||||
controller.AddComponent(potion, types.Appearance{
|
controller.AddComponent(potion, types.Appearance{
|
||||||
Glyph: types.PlainGlyphHolder{"!"},
|
Glyph: types.PlainGlyphHolder{"!"},
|
||||||
ColorSet: types.TileColorSet{
|
ColorSet: types.TileColorSet{
|
||||||
Fg: types.PlainColorHolder{255, 55, 255, 222},
|
Fg: types.PlainColorHolder{255, 55, 255, 222},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
controller.AddComponent(potion, rooms[0].Center) //implicit Coords
|
controller.AddComponent(potion, rooms[0].Center) //implicit Coords
|
||||||
controller.AddComponent(potion, items.Carried{Mass: 5, Bulk: 3})
|
controller.AddComponent(potion, items.Carried{Mass:5, Bulk:3}) //fixme generate from blueprint!
|
||||||
controller.AddComponent(potion, items.Usable{})
|
controller.AddComponent(potion, items.Usable{})
|
||||||
controller.AddComponent(potion, items.Consumable{})
|
controller.AddComponent(potion, items.Consumable{})
|
||||||
controller.AddComponent(potion, ecs.Named{Name: "first potion"})
|
controller.AddComponent(potion, ecs.Named{Name:"first potion"})
|
||||||
|
|
||||||
potion2 := controller.CreateEntity([]ecs.Component{})
|
potion2 := controller.CreateEntity([]ecs.Component{})
|
||||||
controller.AddComponent(potion2, types.Appearance{
|
controller.AddComponent(potion2, types.Appearance{
|
||||||
Glyph: types.PlainGlyphHolder{"!"},
|
Glyph: types.PlainGlyphHolder{Glyph: "!"},
|
||||||
ColorSet: types.TileColorSet{
|
ColorSet: types.TileColorSet{
|
||||||
Fg: types.PlainColorHolder{255, 222, 255, 55},
|
Fg: types.PlainColorHolder{A: 255, R: 222, G: 255, B: 55},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
controller.AddComponent(potion2, rooms[1].Center) //implicit Coords
|
controller.AddComponent(potion2, rooms[1].Center) //implicit Coords
|
||||||
controller.AddComponent(potion2, items.Carried{Mass: 5, Bulk: 3})
|
controller.AddComponent(potion2, items.Carried{Mass:5, Bulk:3})
|
||||||
controller.AddComponent(potion2, items.Usable{})
|
controller.AddComponent(potion2, items.Usable{})
|
||||||
controller.AddComponent(potion2, items.Consumable{})
|
controller.AddComponent(potion2, items.Consumable{})
|
||||||
controller.AddComponent(potion2, ecs.Named{Name: "second potion"})
|
controller.AddComponent(potion2, ecs.Named{Name:"second potion"})
|
||||||
//fixme end setting up items
|
//fixme end setting up items
|
||||||
|
|
||||||
State.Player = player
|
State.Player = player
|
||||||
State.Controller = controller
|
State.Controller = controller
|
||||||
|
|
||||||
screenMgr.AddScreen("inventory", inv.MakeInverntory(player))
|
screenMgr.AddScreen("inventory", inv.MakeInverntory(player))
|
||||||
|
|
||||||
//but every call to bearlibterminal must be wrapped to closure and passed to mainfunc
|
|
||||||
var exit = false
|
|
||||||
for !exit {
|
|
||||||
|
|
||||||
select {
|
//but every call to bearlibterminal must be wrapped to closure and passed to mainfunc
|
||||||
case State.RawInput <- ui.ReadKeyCode():
|
var exit = false
|
||||||
break
|
for !exit {
|
||||||
case pressed := <-State.Input:
|
|
||||||
screenMgr.CurrentScreen.HandleInput(pressed)
|
|
||||||
break
|
|
||||||
//case f := <-State.mainfunc:
|
|
||||||
// f()
|
|
||||||
// break
|
|
||||||
case <-State.Exit:
|
|
||||||
appctx.Logger(mainCtx).Warn().Msg("quitting NOW")
|
|
||||||
exit = true
|
|
||||||
break
|
|
||||||
// не оставляйте default в бесконечном select {} - сожрет всё CPU
|
|
||||||
default:
|
|
||||||
screenMgr.CurrentScreen.Render()
|
|
||||||
blt.Layer(0) //return to base layer
|
|
||||||
blt.Refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
select {
|
||||||
appctx.Logger(mainCtx).Info().Msg("pre-shutdown sequence")
|
case State.RawInput <- ui.ReadKeyCode():
|
||||||
|
break
|
||||||
|
case pressed := <-State.Input:
|
||||||
|
screenMgr.CurrentScreen.HandleInput(pressed)
|
||||||
|
break
|
||||||
|
//case f := <-State.mainfunc:
|
||||||
|
// f()
|
||||||
|
// break
|
||||||
|
case <-State.Exit:
|
||||||
|
appctx.Logger().Warn().Msg("quitting NOW")
|
||||||
|
exit = true
|
||||||
|
break
|
||||||
|
// не оставляйте default в бесконечном select {} - сожрет всё CPU
|
||||||
|
default:
|
||||||
|
screenMgr.CurrentScreen.Render()
|
||||||
|
blt.Layer(0) //return to base layer
|
||||||
|
blt.Refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
appctx.Logger().Info().Msg("pre-shutdown sequence")
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupLayers(mainwindow *mainwindow.MainWindow) {
|
func setupLayers(mainwindow *mainwindow.MainWindow) {
|
||||||
mainwindow.AddLayer("base", 0, "white")
|
mainwindow.AddLayer("base", 0, "white")
|
||||||
mainwindow.AddLayer("overlay", 1, "white")
|
mainwindow.AddLayer("overlay", 1, "white")
|
||||||
mainwindow.AddLayer("menubg", 2, "white")
|
mainwindow.AddLayer("menubg", 2, "white")
|
||||||
mainwindow.AddLayer("menu", 3, "white")
|
mainwindow.AddLayer("menu", 3, "white")
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeInput(ctx context.Context, baseLayer *mainwindow.Layer) {
|
func decodeInput(ctx context.Context, baseLayer *mainwindow.Layer) {
|
||||||
var exit = false
|
var exit = false
|
||||||
var waitForWCspam = true
|
var waitForWCspam = true
|
||||||
for !exit {
|
for !exit {
|
||||||
select {
|
select {
|
||||||
case keycode := <-State.RawInput:
|
case keycode := <-State.RawInput:
|
||||||
if keycode == blt.TK_NONE {
|
if keycode == blt.TK_NONE {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if keycode == blt.TK_CLOSE && !waitForWCspam {
|
if keycode == blt.TK_CLOSE && !waitForWCspam {
|
||||||
appctx.Logger(ctx).Warn().Msg("exiting on window close...")
|
appctx.Logger().Warn().Msg("exiting on window close...")
|
||||||
State.Exit <- struct{}{}
|
State.Exit <- struct{}{}
|
||||||
appctx.Logger(ctx).Warn().Msg("...done")
|
appctx.Logger().Warn().Msg("...done")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var pressed = ""
|
var pressed = ""
|
||||||
var isModifier, _ = util.IntInSlice(keycode, modifiers)
|
var isModifier, _ = util.IntInSlice(keycode, modifiers)
|
||||||
if !isModifier {
|
if !isModifier {
|
||||||
|
|
||||||
pressed = ui.Scancodemap[keycode]
|
pressed = ui.Scancodemap[keycode]
|
||||||
|
|
||||||
if blt.Check(blt.TK_SHIFT) != 0 {
|
if blt.Check(blt.TK_SHIFT) != 0 {
|
||||||
pressed = "Shift+" + pressed
|
pressed = "Shift+" + pressed
|
||||||
}
|
}
|
||||||
if blt.Check(blt.TK_ALT) != 0 {
|
if blt.Check(blt.TK_ALT) != 0 {
|
||||||
pressed = "Alt+" + pressed
|
pressed = "Alt+" + pressed
|
||||||
}
|
}
|
||||||
if blt.Check(blt.TK_CONTROL) != 0 {
|
if blt.Check(blt.TK_CONTROL) != 0 {
|
||||||
pressed = "Ctrl+" + pressed
|
pressed = "Ctrl+" + pressed
|
||||||
}
|
}
|
||||||
|
|
||||||
//global hotkeys
|
//global hotkeys
|
||||||
switch pressed {
|
switch pressed {
|
||||||
case "Ctrl+q":
|
case "Ctrl+q":
|
||||||
//fallthrough
|
//fallthrough
|
||||||
//case "Escape":
|
//case "Escape":
|
||||||
appctx.Logger(ctx).Info().Msg("exiting on quit command...")
|
appctx.Logger().Info().Msg("exiting on quit command...")
|
||||||
State.Exit <- struct{}{}
|
State.Exit <- struct{}{}
|
||||||
appctx.Logger(ctx).Info().Msg("...done")
|
appctx.Logger().Info().Msg("...done")
|
||||||
exit = true
|
exit = true
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
if pressed != "" {
|
if pressed != "" {
|
||||||
waitForWCspam = false
|
waitForWCspam = false;
|
||||||
State.Input <- pressed
|
State.Input <- pressed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "v0.0.1.7",
|
"version": "v0.0.1.7-29-g4f18b6d",
|
||||||
"title": "Alchemyst",
|
"title": "Alchemyst",
|
||||||
"sizeX": 100,
|
"sizeX": 100,
|
||||||
"sizeY": 47,
|
"sizeY": 47,
|
||||||
|
@ -25,7 +25,7 @@ func TestDelaunay(t *testing.T) {
|
|||||||
{types.Coords{10, 10}, types.Coords{30, 10}},
|
{types.Coords{10, 10}, types.Coords{30, 10}},
|
||||||
}
|
}
|
||||||
|
|
||||||
result := delaunay.GetMst(coords, 100, 100, 0)
|
result := delaunay.GetMst(coords, 100, 100, 100 )
|
||||||
|
|
||||||
for idx, _ := range result {
|
for idx, _ := range result {
|
||||||
if result[idx] != expected[idx] {
|
if result[idx] != expected[idx] {
|
||||||
|
@ -3,13 +3,11 @@ package ecs
|
|||||||
// ECS system by jcerise, github.com/jcerise/gogue
|
// ECS system by jcerise, github.com/jcerise/gogue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
ctx context.Context
|
|
||||||
systems map[string]System
|
systems map[string]System
|
||||||
sortedSystems map[int][]System
|
sortedSystems map[int][]System
|
||||||
priorityKeys []int
|
priorityKeys []int
|
||||||
@ -23,8 +21,8 @@ type Controller struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewController is a convenience/constructor method to properly initialize a new processor
|
// NewController is a convenience/constructor method to properly initialize a new processor
|
||||||
func NewController(ctx context.Context) *Controller {
|
func NewController() *Controller {
|
||||||
controller := Controller{ctx: ctx}
|
controller := Controller{}
|
||||||
controller.systems = make(map[string]System)
|
controller.systems = make(map[string]System)
|
||||||
controller.sortedSystems = make(map[int][]System)
|
controller.sortedSystems = make(map[int][]System)
|
||||||
controller.priorityKeys = []int{}
|
controller.priorityKeys = []int{}
|
||||||
@ -80,7 +78,7 @@ func (c *Controller) GetMappedComponentClass(componentName string) Component {
|
|||||||
return c.componentMap[componentName]
|
return c.componentMap[componentName]
|
||||||
} else {
|
} else {
|
||||||
// TODO: Add better (read: actual) error handling here
|
// TODO: Add better (read: actual) error handling here
|
||||||
appctx.Logger(c.ctx).Warn().Msgf("Component[%s] not registered on Controller.\n", componentName)
|
appctx.Logger().Warn().Msgf("Component[%s] not registered on Controller.\n", componentName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,15 +138,20 @@ func (c *Controller) GetEntities() map[Entity]map[string]Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetEntitiesWithComponent returns a list of all entities with a given component attached
|
// GetEntitiesWithComponent returns a list of all entities with a given component attached
|
||||||
// TODO: Allow for passing a list of components
|
func (c *Controller) GetEntitiesWithComponent(componentTypes... string) []Entity {
|
||||||
func (c *Controller) GetEntitiesWithComponent(componentType string) []Entity {
|
|
||||||
entitiesWithComponent := make([]Entity, 0)
|
entitiesWithComponent := make([]Entity, 0)
|
||||||
for entity := range c.entities {
|
for entity := range c.entities {
|
||||||
if c.HasComponent(entity, componentType) {
|
mustAddThis := true
|
||||||
|
for _, componentType := range componentTypes {
|
||||||
|
if !c.HasComponent(entity, componentType) {
|
||||||
|
mustAddThis = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mustAddThis {
|
||||||
entitiesWithComponent = append(entitiesWithComponent, entity)
|
entitiesWithComponent = append(entitiesWithComponent, entity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entitiesWithComponent
|
return entitiesWithComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +211,7 @@ func (c *Controller) AddSystem(system System, priority int) {
|
|||||||
c.sortedSystems[priority] = append(c.sortedSystems[priority], system)
|
c.sortedSystems[priority] = append(c.sortedSystems[priority], system)
|
||||||
sort.Ints(c.priorityKeys)
|
sort.Ints(c.priorityKeys)
|
||||||
} else {
|
} else {
|
||||||
appctx.Logger(c.ctx).Warn().Msgf("A system of type %v was already added to the controller %v!", systemType, c)
|
appctx.Logger().Warn().Msgf("A system of type %v was already added to the controller %v!", systemType, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ func NewLevelRenderSystem(
|
|||||||
return trs
|
return trs
|
||||||
}
|
}
|
||||||
|
|
||||||
//fixme add to screens/game Exit()
|
// fixme add to screens/game Exit()
|
||||||
func (trs LevelRenderSystem) Close() {
|
func (trs LevelRenderSystem) Close() {
|
||||||
trs.animateTiles.Stop()
|
trs.animateTiles.Stop()
|
||||||
trs.animateTiles = nil //zero pointer to ticker
|
trs.animateTiles = nil //zero pointer to ticker
|
||||||
@ -93,7 +93,7 @@ func (trs LevelRenderSystem) Process() {
|
|||||||
//terrain
|
//terrain
|
||||||
for y := 0; y < trs.Viewport.H; y++ {
|
for y := 0; y < trs.Viewport.H; y++ {
|
||||||
for x := 0; x < trs.Viewport.W; x++ {
|
for x := 0; x < trs.Viewport.W; x++ {
|
||||||
mapCoords := types.Coords{trs.Viewport.CameraCoords.X + x, trs.Viewport.CameraCoords.Y + y}
|
mapCoords := types.Coords{X: trs.Viewport.CameraCoords.X + x, Y: trs.Viewport.CameraCoords.Y + y}
|
||||||
|
|
||||||
if trs.state.Level.InBounds(mapCoords) {
|
if trs.state.Level.InBounds(mapCoords) {
|
||||||
tile := trs.state.Level.GetTile(mapCoords)
|
tile := trs.state.Level.GetTile(mapCoords)
|
||||||
|
@ -62,7 +62,7 @@ func (pp *precomputedPermissive) ComputeFov(coords types.Coords, radius int) {
|
|||||||
func (pp *precomputedPermissive) PrecomputeFovMap() {
|
func (pp *precomputedPermissive) PrecomputeFovMap() {
|
||||||
max := pp.MaxTorchRadius
|
max := pp.MaxTorchRadius
|
||||||
minusMax := (-1) * max
|
minusMax := (-1) * max
|
||||||
zeroCoords := types.Coords{0, 0}
|
zeroCoords := types.Coords{X: 0, Y: 0}
|
||||||
var x, y int
|
var x, y int
|
||||||
//fill list
|
//fill list
|
||||||
for x = minusMax; x < max+1; x++ {
|
for x = minusMax; x < max+1; x++ {
|
||||||
@ -70,7 +70,7 @@ func (pp *precomputedPermissive) PrecomputeFovMap() {
|
|||||||
if x == 0 && y == 0 {
|
if x == 0 && y == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
iterCoords := types.Coords{x, y}
|
iterCoords := types.Coords{X: x, Y: y}
|
||||||
distance := zeroCoords.DistanceTo(iterCoords)
|
distance := zeroCoords.DistanceTo(iterCoords)
|
||||||
if distance <= float64(max) {
|
if distance <= float64(max) {
|
||||||
pp.CellList = append(pp.CellList, &Cell{iterCoords, distance, nil})
|
pp.CellList = append(pp.CellList, &Cell{iterCoords, distance, nil})
|
||||||
@ -101,7 +101,7 @@ func (pp *precomputedPermissive) PrecomputeFovMap() {
|
|||||||
roundedX := int(basic.Round(lineX))
|
roundedX := int(basic.Round(lineX))
|
||||||
roundedY := int(basic.Round(lineY))
|
roundedY := int(basic.Round(lineY))
|
||||||
|
|
||||||
idx, cell, err := pp.FindByCoords(types.Coords{roundedX, roundedY})
|
idx, cell, err := pp.FindByCoords(types.Coords{X: roundedX, Y: roundedY})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//inexistent coord found
|
//inexistent coord found
|
||||||
break;
|
break;
|
||||||
|
@ -124,7 +124,9 @@ func (ps *precomputedShade) FindByCoords(c types.Coords) (int, *Cell, error) {
|
|||||||
|
|
||||||
func (ps *precomputedShade) IsInFov(coords types.Coords) bool {
|
func (ps *precomputedShade) IsInFov(coords types.Coords) bool {
|
||||||
rc := ps.fromLevelCoords(coords)
|
rc := ps.fromLevelCoords(coords)
|
||||||
if rc.X == 0 && rc.Y ==0 {return true}
|
if rc.X == 0 && rc.Y == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
_, cell, err := ps.FindByCoords(rc)
|
_, cell, err := ps.FindByCoords(rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
@ -143,15 +145,15 @@ func (ps *precomputedShade) Init() {
|
|||||||
func (ps *precomputedShade) PrecomputeFovMap() {
|
func (ps *precomputedShade) PrecomputeFovMap() {
|
||||||
max := ps.MaxTorchRadius
|
max := ps.MaxTorchRadius
|
||||||
minusMax := (-1) * max
|
minusMax := (-1) * max
|
||||||
zeroCoords := types.Coords{0, 0}
|
zeroCoords := types.Coords{X: 0, Y: 0}
|
||||||
var x, y int
|
var x, y int
|
||||||
//fill list
|
//fill list
|
||||||
for x = minusMax; x < max+1; x++ {
|
for x = minusMax; x < max+1; x++ {
|
||||||
for y = minusMax; y < max+1; y++ {
|
for y = minusMax; y < max+1; y++ {
|
||||||
if x == 0 && y == 0 {
|
if x == 0 && y == 0 {
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
iterCoords := types.Coords{x, y}
|
iterCoords := types.Coords{X: x, Y: y}
|
||||||
distance := zeroCoords.DistanceTo(iterCoords)
|
distance := zeroCoords.DistanceTo(iterCoords)
|
||||||
if distance <= float64(max) {
|
if distance <= float64(max) {
|
||||||
ps.CellList = append(ps.CellList, &Cell{iterCoords, distance, nil, 0})
|
ps.CellList = append(ps.CellList, &Cell{iterCoords, distance, nil, 0})
|
||||||
@ -180,11 +182,11 @@ func (ps *precomputedShade) PrecomputeFovMap() {
|
|||||||
roundedX := int(basic.Round(lineX))
|
roundedX := int(basic.Round(lineX))
|
||||||
roundedY := int(basic.Round(lineY))
|
roundedY := int(basic.Round(lineY))
|
||||||
|
|
||||||
_, cell, err := ps.FindByCoords(types.Coords{roundedX, roundedY})
|
_, cell, err := ps.FindByCoords(types.Coords{X: roundedX, Y: roundedY})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//inexistent coord found
|
//inexistent coord found
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
cell.occludedAngles = unique(append(cell.occludedAngles, i))
|
cell.occludedAngles = unique(append(cell.occludedAngles, i))
|
||||||
}
|
}
|
||||||
@ -219,7 +221,7 @@ func (ps *precomputedShade) recalc(level *gamemap.Level, initCoords types.Coords
|
|||||||
i := 0
|
i := 0
|
||||||
prevDistance := 0.0
|
prevDistance := 0.0
|
||||||
for !bytes.Equal(currentShade, fullShade) {
|
for !bytes.Equal(currentShade, fullShade) {
|
||||||
if (i == len(ps.CellList)-1) {
|
if i == len(ps.CellList)-1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
cell := ps.CellList[i]
|
cell := ps.CellList[i]
|
||||||
@ -242,7 +244,7 @@ func (ps *precomputedShade) recalc(level *gamemap.Level, initCoords types.Coords
|
|||||||
|
|
||||||
if level.GetTile(lc).BlocksSight && ps.LightWalls {
|
if level.GetTile(lc).BlocksSight && ps.LightWalls {
|
||||||
//if (nextShade[angle] == 0 && currentShade[angle] == 0) {
|
//if (nextShade[angle] == 0 && currentShade[angle] == 0) {
|
||||||
if (nextShade[angle] == 0) {
|
if nextShade[angle] == 0 {
|
||||||
level.GetTile(lc).Visible = true
|
level.GetTile(lc).Visible = true
|
||||||
level.GetTile(lc).Explored = true
|
level.GetTile(lc).Explored = true
|
||||||
}
|
}
|
||||||
@ -266,7 +268,7 @@ func (ps *precomputedShade) ComputeFov(level *gamemap.Level, initCoords types.Co
|
|||||||
//fmt.Printf("\n coords: %v, distance: %f, lit: %d", cell.Coords, cell.distance, cell.lit)
|
//fmt.Printf("\n coords: %v, distance: %f, lit: %d", cell.Coords, cell.distance, cell.lit)
|
||||||
cs, err := ps.toLevelCoords(level, initCoords, cell.Coords)
|
cs, err := ps.toLevelCoords(level, initCoords, cell.Coords)
|
||||||
if cell.lit > 0 && cell.lit > MIN_LIT_TO_BE_VISIBLE {
|
if cell.lit > 0 && cell.lit > MIN_LIT_TO_BE_VISIBLE {
|
||||||
//if cell.lit > 0 && cell.lit / (ps.MaxTorchRadius - int(cell.distance - 0.4) - 1) > MIN_LIT_TO_BE_VISIBLE {
|
//if cell.lit > 0 && cell.lit / (ps.MaxTorchRadius - int(cell.distance - 0.4) - 1) > MIN_LIT_TO_BE_VISIBLE {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -298,7 +300,7 @@ func (ps *precomputedShade) ComputeFov(level *gamemap.Level, initCoords types.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ps *precomputedShade) toLevelCoords(level *gamemap.Level, initCoords, relativeCoords types.Coords) (types.Coords, error) {
|
func (ps *precomputedShade) toLevelCoords(level *gamemap.Level, initCoords, relativeCoords types.Coords) (types.Coords, error) {
|
||||||
realCoords := types.Coords{initCoords.X + relativeCoords.X, initCoords.Y + relativeCoords.Y}
|
realCoords := types.Coords{X: initCoords.X + relativeCoords.X, Y: initCoords.Y + relativeCoords.Y}
|
||||||
if !level.InBounds(realCoords) {
|
if !level.InBounds(realCoords) {
|
||||||
return types.Coords{}, errOutOfBounds
|
return types.Coords{}, errOutOfBounds
|
||||||
}
|
}
|
||||||
@ -306,7 +308,7 @@ func (ps *precomputedShade) toLevelCoords(level *gamemap.Level, initCoords, rela
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ps *precomputedShade) fromLevelCoords(lc types.Coords) types.Coords {
|
func (ps *precomputedShade) fromLevelCoords(lc types.Coords) types.Coords {
|
||||||
relativeCoords := types.Coords{lc.X - ps.originCoords.X, lc.Y - ps.originCoords.Y}
|
relativeCoords := types.Coords{X: lc.X - ps.originCoords.X, Y: lc.Y - ps.originCoords.Y}
|
||||||
return relativeCoords
|
return relativeCoords
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestPsDistance(t *testing.T) {
|
func TestPsDistance(t *testing.T) {
|
||||||
iterCoords := types.Coords{0, 0}
|
iterCoords := types.Coords{X: 0, Y: 0}
|
||||||
|
|
||||||
fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{0, 1}))
|
fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{X: 0, Y: 1}))
|
||||||
fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{0, 5}))
|
fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{X: 0, Y: 5}))
|
||||||
fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{3, 3}))
|
fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{X: 3, Y: 3}))
|
||||||
fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{100, 0}))
|
fmt.Printf("\n dto: \t %v", iterCoords.DistanceTo(types.Coords{X: 100, Y: 0}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrecompShade(t *testing.T) {
|
func TestPrecompShade(t *testing.T) {
|
||||||
@ -44,7 +44,7 @@ func TestPrecompShade(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playerCoords := types.Coords{10, 10}
|
playerCoords := types.Coords{X: 10, Y: 10}
|
||||||
|
|
||||||
level.SetTileByXY(8, 12, gamemap.NewWall())
|
level.SetTileByXY(8, 12, gamemap.NewWall())
|
||||||
level.SetTileByXY(10, 8, gamemap.NewWall())
|
level.SetTileByXY(10, 8, gamemap.NewWall())
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package gamemap
|
package gamemap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"fmt"
|
||||||
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||||
@ -14,7 +15,6 @@ var mapHeight = 90
|
|||||||
|
|
||||||
type Level struct {
|
type Level struct {
|
||||||
types.Rect
|
types.Rect
|
||||||
ctx context.Context
|
|
||||||
Name string
|
Name string
|
||||||
Branch string
|
Branch string
|
||||||
Depth int
|
Depth int
|
||||||
@ -30,7 +30,7 @@ func (l *Level) GetTileNbs (coords types.Coords) []*Tile {
|
|||||||
result := make([]*Tile,0)
|
result := make([]*Tile,0)
|
||||||
for i := coords.X-1; i < coords.X+1; i++ {
|
for i := coords.X-1; i < coords.X+1; i++ {
|
||||||
for j := coords.Y-1; j < coords.Y+1; j++ {
|
for j := coords.Y-1; j < coords.Y+1; j++ {
|
||||||
nbc := types.Coords{i,j}
|
nbc := types.Coords{X: i,Y: j}
|
||||||
if l.InBounds(nbc){
|
if l.InBounds(nbc){
|
||||||
if nbc == coords {
|
if nbc == coords {
|
||||||
continue
|
continue
|
||||||
@ -66,34 +66,33 @@ func (l *Level) MakePassByXY (x,y int, tile *Tile) {
|
|||||||
func (l *Level) Put (x, y int, tileFunc interface{}) {
|
func (l *Level) Put (x, y int, tileFunc interface{}) {
|
||||||
tile := tileFunc.(func() *Tile)()
|
tile := tileFunc.(func() *Tile)()
|
||||||
if tile == nil {
|
if tile == nil {
|
||||||
appctx.Logger(l.ctx).Fatal().Msgf("Got non-tile type to put into level: %v", tile)
|
appctx.Logger().Fatal().Msgf("Got non-tile type to put into level: %v", tile)
|
||||||
}
|
}
|
||||||
if l.InBounds(types.Coords{x, y}) {
|
if l.InBounds(types.Coords{X: x, Y: y}) {
|
||||||
l.Tiles[y*l.W+x] = tile
|
l.Tiles[y*l.W+x] = tile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLevel(ctx context.Context, branch string, depth int) *Level {
|
func NewLevel(branch string, depth int) *Level {
|
||||||
l := &Level{
|
l := &Level{
|
||||||
ctx: ctx,
|
Name: fmt.Sprintf(branch, depth),
|
||||||
Name: branch + string(depth),
|
|
||||||
Depth: depth,
|
Depth: depth,
|
||||||
Rect: types.NewRect(0,0, mapWidth, mapHeight),
|
Rect: types.NewRect(0,0, mapWidth, mapHeight),
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Tiles = make([]*Tile, l.W*l.H)
|
l.Tiles = make([]*Tile, l.W*l.H)
|
||||||
appctx.Logger(ctx).Debug().Msgf("Generating level of branch %s depth %d", branch, depth)
|
appctx.Logger().Debug().Msgf("Generating level of branch %s depth %d", branch, depth)
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Level) SetAllInvisible() {
|
func (l *Level) SetAllInvisible() {
|
||||||
for idx, _ := range l.Tiles {
|
for idx := range l.Tiles {
|
||||||
l.Tiles[idx].Visible = false
|
l.Tiles[idx].Visible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Level) SetAllVisible() {
|
func (l *Level) SetAllVisible() {
|
||||||
for idx, _ := range l.Tiles {
|
for idx := range l.Tiles {
|
||||||
l.Tiles[idx].Visible = true
|
l.Tiles[idx].Visible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package mapgens
|
package mapgens
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util"
|
"lab.zaar.be/thefish/alchemyst-go/util"
|
||||||
@ -14,7 +13,7 @@ var maxRoomSize = 22
|
|||||||
var maxrooms = 100
|
var maxrooms = 100
|
||||||
|
|
||||||
var fges = map[int]types.RectFill{
|
var fges = map[int]types.RectFill{
|
||||||
1: types.RectFill{
|
1: {
|
||||||
Top: gamemap.NewWall,
|
Top: gamemap.NewWall,
|
||||||
Bottom: gamemap.NewWall,
|
Bottom: gamemap.NewWall,
|
||||||
Left: gamemap.NewWall,
|
Left: gamemap.NewWall,
|
||||||
@ -26,7 +25,7 @@ var fges = map[int]types.RectFill{
|
|||||||
Body: gamemap.NewFloor,
|
Body: gamemap.NewFloor,
|
||||||
},
|
},
|
||||||
|
|
||||||
2: types.RectFill{
|
2: {
|
||||||
Top: gamemap.NewWaterTile,
|
Top: gamemap.NewWaterTile,
|
||||||
Bottom: gamemap.NewWaterTile,
|
Bottom: gamemap.NewWaterTile,
|
||||||
Left: gamemap.NewWaterTile,
|
Left: gamemap.NewWaterTile,
|
||||||
@ -39,9 +38,9 @@ var fges = map[int]types.RectFill{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRandomRoomList(ctx context.Context, rng *util.RNG, l *gamemap.Level, maxRooms, minRoomSize, maxRoomSize int, ) []gamemap.Room{
|
func GetRandomRoomList(rng *util.RNG, l *gamemap.Level, maxRooms, minRoomSize, maxRoomSize int, ) []gamemap.Room{
|
||||||
rooms := make([]gamemap.Room, 0)
|
rooms := make([]gamemap.Room, 0)
|
||||||
pfLoader := gamemap.NewPrefabLoader(ctx)
|
pfLoader := gamemap.NewPrefabLoader()
|
||||||
pfRooms := pfLoader.PrefabRoomsList()
|
pfRooms := pfLoader.PrefabRoomsList()
|
||||||
|
|
||||||
var fillage types.RectFill
|
var fillage types.RectFill
|
||||||
@ -54,7 +53,14 @@ func GetRandomRoomList(ctx context.Context, rng *util.RNG, l *gamemap.Level, max
|
|||||||
|
|
||||||
|
|
||||||
var newRoom = gamemap.Room{}
|
var newRoom = gamemap.Room{}
|
||||||
if !prefabUsed || rng.Range(0, 5) > 3 {
|
if prefabUsed && rng.Range(0, 5) <= 3 {
|
||||||
|
newRoom = gamemap.NewRandomRectRoom(
|
||||||
|
rng,
|
||||||
|
rng.Range(minRoomSize, maxRoomSize),
|
||||||
|
rng.Range(minRoomSize, maxRoomSize),
|
||||||
|
fillage,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
//if prefabUsed {
|
//if prefabUsed {
|
||||||
//prefab
|
//prefab
|
||||||
prefabUsed = true
|
prefabUsed = true
|
||||||
@ -68,20 +74,14 @@ func GetRandomRoomList(ctx context.Context, rng *util.RNG, l *gamemap.Level, max
|
|||||||
Mobs: r.Mobs,
|
Mobs: r.Mobs,
|
||||||
Connectors: make([]types.Coords,0),
|
Connectors: make([]types.Coords,0),
|
||||||
}
|
}
|
||||||
for _, coord := range r.Connectors {
|
newRoom.Connectors = append(newRoom.Connectors, r.Connectors...)
|
||||||
newRoom.Connectors = append(newRoom.Connectors, coord)
|
// for _, coord := range r.Connectors {
|
||||||
}
|
// newRoom.Connectors = append(newRoom.Connectors, coord)
|
||||||
} else {
|
// }
|
||||||
newRoom = gamemap.NewRandomRectRoom(
|
|
||||||
rng,
|
|
||||||
rng.Range(minRoomSize, maxRoomSize),
|
|
||||||
rng.Range(minRoomSize, maxRoomSize),
|
|
||||||
fillage,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
where := types.Coords{
|
where := types.Coords{
|
||||||
rng.Range(1, l.W-2-newRoom.W),
|
X: rng.Range(1, l.W-2-newRoom.W),
|
||||||
rng.Range(1, l.H-2-newRoom.H),
|
Y: rng.Range(1, l.H-2-newRoom.H),
|
||||||
}
|
}
|
||||||
|
|
||||||
newRoom.MoveToCoords(where)
|
newRoom.MoveToCoords(where)
|
||||||
@ -102,11 +102,12 @@ func GetRandomRoomList(ctx context.Context, rng *util.RNG, l *gamemap.Level, max
|
|||||||
return rooms
|
return rooms
|
||||||
}
|
}
|
||||||
|
|
||||||
func BlitToLevel (ctx context.Context, l *gamemap.Level, rooms[]gamemap.Room) {
|
//fixme overlapping rooms
|
||||||
|
func BlitToLevel (l *gamemap.Level, rooms[]gamemap.Room) {
|
||||||
for _, room := range rooms {
|
for _, room := range rooms {
|
||||||
err := room.BlitToLevel(ctx, l)
|
err := room.BlitToLevel(l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
appctx.Logger(ctx).Err(err)
|
appctx.Logger().Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,7 +173,7 @@ func DigHTunnel(l *gamemap.Level, x1, x2, y int) {
|
|||||||
finish = x1
|
finish = x1
|
||||||
}
|
}
|
||||||
for i := start; i <= finish; i++ {
|
for i := start; i <= finish; i++ {
|
||||||
if l.InBounds(types.Coords{i, y}) {
|
if l.InBounds(types.Coords{X: i, Y: y}) {
|
||||||
l.MakePassByXY(i, y, gamemap.NewFloor())
|
l.MakePassByXY(i, y, gamemap.NewFloor())
|
||||||
//l.Tiles[i][y] = gamemap.NewFloor()
|
//l.Tiles[i][y] = gamemap.NewFloor()
|
||||||
}
|
}
|
||||||
@ -189,7 +190,7 @@ func DigVTunnel(l *gamemap.Level, y1, y2, x int) {
|
|||||||
finish = y1
|
finish = y1
|
||||||
}
|
}
|
||||||
for i := start; i <= finish; i++ {
|
for i := start; i <= finish; i++ {
|
||||||
if l.InBounds(types.Coords{x, i}) {
|
if l.InBounds(types.Coords{X: x, Y: i}) {
|
||||||
l.MakePassByXY(x, i, gamemap.NewFloor())
|
l.MakePassByXY(x, i, gamemap.NewFloor())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,9 @@ package mapgens
|
|||||||
import (
|
import (
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util"
|
"lab.zaar.be/thefish/alchemyst-go/util"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func DefaultGen(ctx appctx.ClientCtx,l *gamemap.Level) (*gamemap.Level, []gamemap.Room) {
|
func DefaultGen(l *gamemap.Level) (*gamemap.Level, []gamemap.Room) {
|
||||||
|
|
||||||
rng := util.NewRNG()
|
rng := util.NewRNG()
|
||||||
|
|
||||||
@ -17,9 +16,9 @@ func DefaultGen(ctx appctx.ClientCtx,l *gamemap.Level) (*gamemap.Level, []gamema
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rooms := GetRandomRoomList(ctx, rng, l, maxrooms, minRoomSize, maxRoomSize)
|
rooms := GetRandomRoomList(rng, l, maxrooms, minRoomSize, maxRoomSize)
|
||||||
|
|
||||||
BlitToLevel(ctx, l, rooms)
|
BlitToLevel(l, rooms)
|
||||||
|
|
||||||
for idx, room := range rooms {
|
for idx, room := range rooms {
|
||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
|
@ -18,10 +18,10 @@ func DelaunayMstGen(ctx context.Context, l *gamemap.Level) (*gamemap.Level, []ga
|
|||||||
l.SetTileByXY(i, j, gamemap.NewWall())
|
l.SetTileByXY(i, j, gamemap.NewWall())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rooms := GetRandomRoomList(ctx, rng, l, maxrooms, minRoomSize, maxRoomSize)
|
rooms := GetRandomRoomList(rng, l, maxrooms, minRoomSize, maxRoomSize)
|
||||||
|
|
||||||
|
|
||||||
BlitToLevel(ctx, l, rooms)
|
BlitToLevel(l, rooms)
|
||||||
|
|
||||||
centers := make([]types.Coords, 0)
|
centers := make([]types.Coords, 0)
|
||||||
for _, room := range rooms {
|
for _, room := range rooms {
|
||||||
|
@ -4,11 +4,10 @@ import (
|
|||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util"
|
"lab.zaar.be/thefish/alchemyst-go/util"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/delaunay"
|
"lab.zaar.be/thefish/alchemyst-go/util/delaunay"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DelaunayMstExtGen(ctx appctx.ClientCtx, l *gamemap.Level) (*gamemap.Level, []gamemap.Room) {
|
func DelaunayMstExtGen(l *gamemap.Level) (*gamemap.Level, []gamemap.Room) {
|
||||||
|
|
||||||
rng := util.NewRNG()
|
rng := util.NewRNG()
|
||||||
|
|
||||||
@ -18,9 +17,9 @@ func DelaunayMstExtGen(ctx appctx.ClientCtx, l *gamemap.Level) (*gamemap.Level,
|
|||||||
l.SetTileByXY(i, j, gamemap.NewWall())
|
l.SetTileByXY(i, j, gamemap.NewWall())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rooms := GetRandomRoomList(ctx, rng, l, maxrooms, minRoomSize, maxRoomSize)
|
rooms := GetRandomRoomList(rng, l, maxrooms, minRoomSize, maxRoomSize)
|
||||||
|
|
||||||
BlitToLevel(ctx, l, rooms)
|
BlitToLevel(l, rooms)
|
||||||
|
|
||||||
centers := make([]types.Coords, 0)
|
centers := make([]types.Coords, 0)
|
||||||
for _, room := range rooms {
|
for _, room := range rooms {
|
||||||
|
@ -18,9 +18,9 @@ func DelaunayPureGen(ctx context.Context, l *gamemap.Level) (*gamemap.Level, []g
|
|||||||
l.SetTileByXY(i, j, gamemap.NewWall())
|
l.SetTileByXY(i, j, gamemap.NewWall())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rooms := GetRandomRoomList(ctx, rng, l, maxrooms, minRoomSize, maxRoomSize)
|
rooms := GetRandomRoomList(rng, l, maxrooms, minRoomSize, maxRoomSize)
|
||||||
|
|
||||||
BlitToLevel(ctx, l, rooms)
|
BlitToLevel(l, rooms)
|
||||||
|
|
||||||
centers := make([]types.Coords, 0)
|
centers := make([]types.Coords, 0)
|
||||||
for _, room := range rooms {
|
for _, room := range rooms {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package gamemap
|
package gamemap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"os"
|
||||||
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/items"
|
"lab.zaar.be/thefish/alchemyst-go/engine/items"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
@ -30,7 +30,7 @@ type PrefabRecord struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LoadPrefabFile(filename string) (*PrefabFile, error) {
|
func LoadPrefabFile(filename string) (*PrefabFile, error) {
|
||||||
data, err := ioutil.ReadFile(filename)
|
data, err := os.ReadFile(filename)
|
||||||
if err!= nil {
|
if err!= nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -42,12 +42,10 @@ func LoadPrefabFile(filename string) (*PrefabFile, error) {
|
|||||||
return instance, nil
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrefabLoader struct {
|
type PrefabLoader struct {}
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPrefabLoader(ctx context.Context) PrefabLoader {
|
func NewPrefabLoader() PrefabLoader {
|
||||||
return PrefabLoader{ctx: ctx}
|
return PrefabLoader{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pfbl PrefabLoader) PrefabRoomsList() []Room {
|
func (pfbl PrefabLoader) PrefabRoomsList() []Room {
|
||||||
@ -65,6 +63,8 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
|
|||||||
|
|
||||||
for _, rawPrefab := range file.Prefabs {
|
for _, rawPrefab := range file.Prefabs {
|
||||||
|
|
||||||
|
appctx.Logger().Debug().Msgf("adding %s", rawPrefab.name)
|
||||||
|
|
||||||
for k,v := range rawPrefab.TileLegend {
|
for k,v := range rawPrefab.TileLegend {
|
||||||
currentTileLegend[k] = v
|
currentTileLegend[k] = v
|
||||||
}
|
}
|
||||||
@ -76,8 +76,8 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
room := Room{
|
room := Room{
|
||||||
Rect:types.Rect{0, 0, rawPrefab.Size.X, rawPrefab.Size.Y},
|
Rect:types.Rect{X: 0, Y: 0, W: rawPrefab.Size.X, H: rawPrefab.Size.Y},
|
||||||
Center: types.Coords{rawPrefab.Size.X / 2, rawPrefab.Size.Y / 2}, //fixme
|
Center: types.Coords{X: rawPrefab.Size.X / 2, Y: rawPrefab.Size.Y / 2}, //fixme
|
||||||
Geometry: make([]func()*Tile, rawPrefab.Size.X*rawPrefab.Size.Y),
|
Geometry: make([]func()*Tile, rawPrefab.Size.X*rawPrefab.Size.Y),
|
||||||
Mobs: make([]mob.Mob, rawPrefab.Size.X*rawPrefab.Size.Y),
|
Mobs: make([]mob.Mob, rawPrefab.Size.X*rawPrefab.Size.Y),
|
||||||
Items: make([]items.Carried, rawPrefab.Size.X*rawPrefab.Size.Y),
|
Items: make([]items.Carried, rawPrefab.Size.X*rawPrefab.Size.Y),
|
||||||
@ -102,11 +102,11 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
|
|||||||
}
|
}
|
||||||
if shortName == "connector" {
|
if shortName == "connector" {
|
||||||
f = NewWall
|
f = NewWall
|
||||||
room.Connectors = append(room.Connectors, types.Coords{i,j})
|
room.Connectors = append(room.Connectors, types.Coords{X: i,Y: j})
|
||||||
} else {
|
} else {
|
||||||
f, ok = TileTypeMap[shortName]
|
f, ok = TileTypeMap[shortName]
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
appctx.Logger(pfbl.ctx).Warn().Msgf("Unknown tile: %s", shortName)
|
appctx.Logger().Warn().Msgf("Unknown tile: %s", shortName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
room.Geometry[i+ j*room.W] = f
|
room.Geometry[i+ j*room.W] = f
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package gamemap
|
package gamemap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/items"
|
"lab.zaar.be/thefish/alchemyst-go/engine/items"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util"
|
"lab.zaar.be/thefish/alchemyst-go/util"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var invalidBlit = errors.New("trying to blit on existing good tile")
|
var invalidBlit = errors.New("trying to blit on existing good tile")
|
||||||
@ -28,19 +28,19 @@ func (r *Room) Put (x, y int, tileFunc interface{}) {
|
|||||||
if tf == nil {
|
if tf == nil {
|
||||||
return //fixme error
|
return //fixme error
|
||||||
}
|
}
|
||||||
if r.InBounds(types.Coords{x, y}) {
|
if r.InBounds(types.Coords{X: x, Y: y}) {
|
||||||
r.Geometry[x+y*r.W] = tf
|
r.Geometry[x+y*r.W] = tf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (room *Room) BlitToLevel(ctx context.Context, l *Level) error {
|
func (room *Room) BlitToLevel(l *Level) error {
|
||||||
//copy tiles like this:
|
//copy tiles like this:
|
||||||
//https://stackoverflow.com/questions/21011023/copy-pointer-values-a-b-in-golang
|
//https://stackoverflow.com/questions/21011023/copy-pointer-values-a-b-in-golang
|
||||||
|
|
||||||
for j := 0; j < room.H; j++ {
|
for j := 0; j < room.H; j++ {
|
||||||
|
|
||||||
for i := 0; i < room.W; i++ {
|
for i := 0; i < room.W; i++ {
|
||||||
mapCoords := types.Coords{room.X + i, room.Y + j}
|
mapCoords := types.Coords{X: room.X + i, Y: room.Y + j}
|
||||||
underlyingTile := l.GetTile(mapCoords)
|
underlyingTile := l.GetTile(mapCoords)
|
||||||
|
|
||||||
tileFunc := room.Geometry[i+j*room.W]
|
tileFunc := room.Geometry[i+j*room.W]
|
||||||
@ -51,7 +51,7 @@ func (room *Room) BlitToLevel(ctx context.Context, l *Level) error {
|
|||||||
//check underlying tile
|
//check underlying tile
|
||||||
if underlyingTile == nil ||
|
if underlyingTile == nil ||
|
||||||
underlyingTile.Name != "Wall" {
|
underlyingTile.Name != "Wall" {
|
||||||
appctx.Logger(ctx).Warn().Msg("Invalid blit!")
|
appctx.Logger().Warn().Msg("Invalid blit!")
|
||||||
return invalidBlit
|
return invalidBlit
|
||||||
}
|
}
|
||||||
l.Put(mapCoords.X, mapCoords.Y, tileFunc)
|
l.Put(mapCoords.X, mapCoords.Y, tileFunc)
|
||||||
@ -86,17 +86,17 @@ func NewRandomRectRoom(rng *util.RNG, w, h int, fillage types.RectFill) Room {
|
|||||||
w,
|
w,
|
||||||
h,
|
h,
|
||||||
),
|
),
|
||||||
Center: types.Coords{w / 2, h /2 },
|
Center: types.Coords{X: w / 2, Y: h /2 },
|
||||||
Geometry: make([]func()*Tile, w*h),
|
Geometry: make([]func()*Tile, w*h),
|
||||||
}
|
}
|
||||||
newRoom.Blit(fillage, &newRoom)
|
newRoom.Blit(fillage, &newRoom)
|
||||||
//add connectors
|
//add connectors
|
||||||
newRoom.Connectors = append(
|
newRoom.Connectors = append(
|
||||||
newRoom.Connectors,
|
newRoom.Connectors,
|
||||||
types.Coords{rng.Range(1, w - 2), 1},
|
types.Coords{X: rng.Range(1, w - 2), Y: 1},
|
||||||
types.Coords{rng.Range(1, w - 2), h -2},
|
types.Coords{X: rng.Range(1, w - 2), Y: h -2},
|
||||||
types.Coords{1, rng.Range(1, h - 2)},
|
types.Coords{X: 1, Y: rng.Range(1, h - 2)},
|
||||||
types.Coords{w - 2, rng.Range(1, h - 2)},
|
types.Coords{X: w - 2, Y: rng.Range(1, h - 2)},
|
||||||
)
|
)
|
||||||
return newRoom
|
return newRoom
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ func (r *Room) String() string {
|
|||||||
return strings.Join([]string{
|
return strings.Join([]string{
|
||||||
"room: ",
|
"room: ",
|
||||||
"\t" + fmt.Sprintf(" rect: X: %d, Y: %d, maxX: %d, maxY: %d", r.Rect.X, r.Rect.Y, r.Rect.W + r.X - 1, r.Rect.H + r.Y - 1),
|
"\t" + fmt.Sprintf(" rect: X: %d, Y: %d, maxX: %d, maxY: %d", r.Rect.X, r.Rect.Y, r.Rect.W + r.X - 1, r.Rect.H + r.Y - 1),
|
||||||
"\t" + fmt.Sprintf(" center:", r.Center.X, r.Center.Y),
|
"\t" + fmt.Sprintf(" center: %d, %d", r.Center.X, r.Center.Y),
|
||||||
"\t" + fmt.Sprintf(" Connectors: %v", r.Connectors),
|
"\t" + fmt.Sprintf(" Connectors: %v", r.Connectors),
|
||||||
},"\n") + "\n"
|
},"\n") + "\n"
|
||||||
}
|
}
|
@ -37,21 +37,22 @@ func (t *Tile) GetRawBgColor() uint32 {
|
|||||||
|
|
||||||
func NewWall() *Tile {
|
func NewWall() *Tile {
|
||||||
return &Tile{
|
return &Tile{
|
||||||
|
Appearance: &Appearance{
|
||||||
|
Glyph: &PlainGlyphHolder{Glyph: "#"},
|
||||||
|
ColorSet: TileColorSet{
|
||||||
|
Fg: &PlainColorHolder{A: 255, R: 130, G: 110, B: 150},
|
||||||
|
Bg: &PlainColorHolder{A: 255, R: 172, G: 170, B: 173},
|
||||||
|
DarkFg: &PlainColorHolder{A: 255, R: 20, G: 20, B: 68},
|
||||||
|
DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
|
||||||
|
},
|
||||||
|
},
|
||||||
Name: "Wall",
|
Name: "Wall",
|
||||||
Description: "A dull rock wall",
|
Description: "A dull rock wall",
|
||||||
BlocksPass: true,
|
BlocksPass: true,
|
||||||
BlocksSight: true,
|
BlocksSight: true,
|
||||||
Explored: false,
|
Explored: false,
|
||||||
MustDraw: false,
|
MustDraw: false,
|
||||||
Appearance: &Appearance{
|
Visible: false,
|
||||||
Glyph: &PlainGlyphHolder{"#"},
|
|
||||||
ColorSet: TileColorSet{
|
|
||||||
Fg: &PlainColorHolder{255, 130, 110, 150},
|
|
||||||
Bg: &PlainColorHolder{255, 172, 170, 173},
|
|
||||||
DarkFg: &PlainColorHolder{255, 20, 20, 68},
|
|
||||||
DarkBg: &PlainColorHolder{255, 7, 7, 30},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,18 +65,18 @@ func NewDecoratedWall() *Tile {
|
|||||||
Explored: false,
|
Explored: false,
|
||||||
MustDraw: false,
|
MustDraw: false,
|
||||||
Appearance: &Appearance{
|
Appearance: &Appearance{
|
||||||
Glyph: &PlainGlyphHolder{"#"},
|
Glyph: &PlainGlyphHolder{Glyph: "#"},
|
||||||
ColorSet: TileColorSet{
|
ColorSet: TileColorSet{
|
||||||
Fg: &PlainColorHolder{255, 130, 110, 150},
|
Fg: &PlainColorHolder{A: 255, R: 130, G: 110, B: 150},
|
||||||
//Bg: &PlainColorHolder{255, 172, 170, 173},
|
//Bg: &PlainColorHolder{255, 172, 170, 173},
|
||||||
Bg: &DanceColorHolder{
|
Bg: &DanceColorHolder{
|
||||||
255,
|
A: 255,
|
||||||
DeviatedColorRing(172, -15, 10),
|
R: DeviatedColorRing(172, -15, 10),
|
||||||
DeviatedColorRing(170, -5, 15),
|
G: DeviatedColorRing(170, -5, 15),
|
||||||
DeviatedColorRing(173, -10, 10),
|
B: DeviatedColorRing(173, -10, 10),
|
||||||
},
|
},
|
||||||
DarkFg: &PlainColorHolder{255, 20, 20, 68},
|
DarkFg: &PlainColorHolder{A: 255, R: 20, G: 20, B: 68},
|
||||||
DarkBg: &PlainColorHolder{255, 7, 7, 30},
|
DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -90,12 +91,12 @@ func NewFloor() *Tile {
|
|||||||
Explored: false,
|
Explored: false,
|
||||||
MustDraw: false,
|
MustDraw: false,
|
||||||
Appearance: &Appearance{
|
Appearance: &Appearance{
|
||||||
Glyph: &PlainGlyphHolder{"."},
|
Glyph: &PlainGlyphHolder{Glyph: "."},
|
||||||
ColorSet: TileColorSet{
|
ColorSet: TileColorSet{
|
||||||
Fg: &PlainColorHolder{255, 220, 220, 250},
|
Fg: &PlainColorHolder{A: 255, R: 220, G: 220, B: 250},
|
||||||
Bg: &PlainColorHolder{255, 19, 19, 70},
|
Bg: &PlainColorHolder{A: 255, R: 19, G: 19, B: 70},
|
||||||
DarkFg: &PlainColorHolder{255, 30, 20, 50},
|
DarkFg: &PlainColorHolder{A: 255, R: 30, G: 20, B: 50},
|
||||||
DarkBg: &PlainColorHolder{255, 7, 7, 30},
|
DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -111,17 +112,17 @@ func NewWaterTile() *Tile {
|
|||||||
Explored: false,
|
Explored: false,
|
||||||
MustDraw: true, //fixme debug
|
MustDraw: true, //fixme debug
|
||||||
Appearance: &Appearance{
|
Appearance: &Appearance{
|
||||||
Glyph: &PlainGlyphHolder{" "},
|
Glyph: &PlainGlyphHolder{Glyph: " "},
|
||||||
ColorSet: TileColorSet{
|
ColorSet: TileColorSet{
|
||||||
Fg: &PlainColorHolder{255, 220, 220, 250},
|
Fg: &PlainColorHolder{A: 255, R: 220, G: 220, B: 250},
|
||||||
Bg: &DanceColorHolder{
|
Bg: &DanceColorHolder{
|
||||||
255,
|
A: 255,
|
||||||
SingleColorRing(5),
|
R: SingleColorRing(5),
|
||||||
FillColorRing(2, 2, 42, 4),
|
G: FillColorRing(2, 2, 42, 4),
|
||||||
FillColorRing(154, 150, 229, 12),
|
B: FillColorRing(154, 150, 229, 12),
|
||||||
},
|
},
|
||||||
DarkFg: &PlainColorHolder{255, 30, 20, 50},
|
DarkFg: &PlainColorHolder{A: 255, R: 30, G: 20, B: 50},
|
||||||
DarkBg: &PlainColorHolder{255, 7, 7, 30},
|
DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -131,27 +132,21 @@ func NewWaterTile() *Tile {
|
|||||||
func NewDeepWaterTile() *Tile {
|
func NewDeepWaterTile() *Tile {
|
||||||
//ch := &ColorHolder{5, 2, 154}
|
//ch := &ColorHolder{5, 2, 154}
|
||||||
return &Tile{
|
return &Tile{
|
||||||
|
Appearance: &Appearance{
|
||||||
|
Glyph: &PlainGlyphHolder{Glyph: " "},
|
||||||
|
ColorSet: TileColorSet{
|
||||||
|
Fg: &PlainColorHolder{A: 255, R: 220, G: 220, B: 250},
|
||||||
|
Bg: &DanceColorHolder{A: 255, R: SingleColorRing(19), G: FillColorRing(19, 0, 15, 2), B: FillColorRing(127, 120, 176, 12)},
|
||||||
|
DarkFg: &PlainColorHolder{A: 255, R: 30, G: 20, B: 50},
|
||||||
|
DarkBg: &PlainColorHolder{A: 255, R: 7, G: 7, B: 30},
|
||||||
|
},
|
||||||
|
},
|
||||||
Name: "Deep Water",
|
Name: "Deep Water",
|
||||||
Description: "Deep water",
|
Description: "Deep water",
|
||||||
BlocksPass: false,
|
BlocksPass: false,
|
||||||
BlocksSight: false,
|
BlocksSight: false,
|
||||||
Explored: false,
|
Explored: false,
|
||||||
MustDraw: true, //fixme debug
|
MustDraw: true,
|
||||||
|
Visible: false,
|
||||||
Appearance: &Appearance{
|
|
||||||
Glyph: &PlainGlyphHolder{" "},
|
|
||||||
ColorSet: TileColorSet{
|
|
||||||
Fg: &PlainColorHolder{255, 220, 220, 250},
|
|
||||||
Bg: &DanceColorHolder{
|
|
||||||
255,
|
|
||||||
SingleColorRing(19),
|
|
||||||
FillColorRing(19, 0, 15, 2),
|
|
||||||
FillColorRing(127, 120, 176, 12),
|
|
||||||
},
|
|
||||||
DarkFg: &PlainColorHolder{255, 30, 20, 50},
|
|
||||||
DarkBg: &PlainColorHolder{255, 7, 7, 30},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
package items
|
package items
|
||||||
|
|
||||||
import "lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
ErrorInvTooHeavy = fmt.Errorf("too heavy")
|
||||||
|
ErrorInvTooBulky = fmt.Errorf("too bulky")
|
||||||
|
)
|
||||||
type Backpack struct {
|
type Backpack struct {
|
||||||
MaxNumber int
|
MaxNumber int
|
||||||
MaxBulk int
|
MaxBulk int
|
||||||
@ -13,7 +19,7 @@ func (b Backpack) Type() string {
|
|||||||
return ecs.BackpackComponent
|
return ecs.BackpackComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backpack) HasFreeSpace(Bulk, Mass int) bool {
|
func (b *Backpack) HasFreeSpace(Bulk, Mass int) error {
|
||||||
totalBulk, totalMass := 0, 0
|
totalBulk, totalMass := 0, 0
|
||||||
for i, _ := range b.items {
|
for i, _ := range b.items {
|
||||||
tmp := Controller.GetComponent(b.items[i], Carried{}.Type()).(Carried)
|
tmp := Controller.GetComponent(b.items[i], Carried{}.Type()).(Carried)
|
||||||
@ -22,14 +28,12 @@ func (b *Backpack) HasFreeSpace(Bulk, Mass int) bool {
|
|||||||
totalMass += carried.Mass
|
totalMass += carried.Mass
|
||||||
}
|
}
|
||||||
if totalMass >= b.MaxMass {
|
if totalMass >= b.MaxMass {
|
||||||
//fixme return message along - 'too heavy'
|
return ErrorInvTooHeavy
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
if totalBulk >= b.MaxMass {
|
if totalBulk >= b.MaxBulk {
|
||||||
//fixme return message along - 'doesnt fit to your backpack'
|
return ErrorInvTooBulky
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backpack) GetItems() []ecs.Entity {
|
func (b *Backpack) GetItems() []ecs.Entity {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package items
|
package items
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
)
|
)
|
||||||
@ -19,32 +20,33 @@ func (c Carried) Type() string {
|
|||||||
return ecs.CarriedComponent
|
return ecs.CarriedComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Carried) Pickup(who, what ecs.Entity) {
|
func (c Carried) Pickup(who, what ecs.Entity) error {
|
||||||
// check if im lying on ground
|
// check if im lying on ground
|
||||||
if !Controller.HasComponent(what, ecs.CoordsComponent) {
|
if !Controller.HasComponent(what, ecs.CoordsComponent) {
|
||||||
return
|
return fmt.Errorf("bug! item with no coords?!")
|
||||||
}
|
}
|
||||||
// something inexistent on map trying to pickup an item?!
|
// something inexistent on map trying to pickup an item?!
|
||||||
if !Controller.HasComponent(who, ecs.CoordsComponent) {
|
if !Controller.HasComponent(who, ecs.CoordsComponent) {
|
||||||
//todo log error - investigate this situation
|
//todo log error - investigate this situation
|
||||||
return
|
return fmt.Errorf("bug! actor with no coords?!")
|
||||||
}
|
}
|
||||||
//check if who and what are on the same tile
|
//check if who and what are in adjacent tiles
|
||||||
whoCoords := Controller.GetComponent(who, ecs.CoordsComponent).(types.Coords)
|
whoCoords := Controller.GetComponent(who, ecs.CoordsComponent).(types.Coords)
|
||||||
whatCoords := Controller.GetComponent(what, ecs.CoordsComponent).(types.Coords)
|
whatCoords := Controller.GetComponent(what, ecs.CoordsComponent).(types.Coords)
|
||||||
if whoCoords != whatCoords {
|
if !whoCoords.IsAdjacentTo(&whatCoords) {
|
||||||
//todo log error - something strange happened
|
//todo log error - something strange happened
|
||||||
return
|
return fmt.Errorf("bug! actor and item in inadjacent coords?!")
|
||||||
}
|
}
|
||||||
//does not have inventory?
|
//does not have inventory?
|
||||||
if !Controller.HasComponent(who, ecs.BackpackComponent) {
|
if !Controller.HasComponent(who, ecs.BackpackComponent) {
|
||||||
//todo send message - you cant carry items
|
//todo send message - you cant carry items
|
||||||
return
|
return fmt.Errorf("bug! actor cannot carry items")
|
||||||
}
|
}
|
||||||
bp := Controller.GetComponent(who, Backpack{}.Type()).(Backpack)
|
bp := Controller.GetComponent(who, Backpack{}.Type()).(Backpack)
|
||||||
if !bp.HasFreeSpace(c.Bulk, c.Mass) {
|
err := bp.HasFreeSpace(c.Bulk, c.Mass)
|
||||||
|
if err != nil {
|
||||||
//todo send message - does not fit to your inventory
|
//todo send message - does not fit to your inventory
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
//do not remove appearance
|
//do not remove appearance
|
||||||
//remove coords instead (does not exist on map anymore)
|
//remove coords instead (does not exist on map anymore)
|
||||||
@ -52,6 +54,7 @@ func (c Carried) Pickup(who, what ecs.Entity) {
|
|||||||
bp.items = append(bp.items, what)
|
bp.items = append(bp.items, what)
|
||||||
//fuck that, we need to update constantly
|
//fuck that, we need to update constantly
|
||||||
Controller.UpdateComponent(who, ecs.BackpackComponent, bp)
|
Controller.UpdateComponent(who, ecs.BackpackComponent, bp)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Carried) Drop(who, what ecs.Entity) {
|
func (c Carried) Drop(who, what ecs.Entity) {
|
||||||
@ -90,13 +93,14 @@ func (c *Carried) GetBulk(what ecs.Entity) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FindCarriedUnder(who ecs.Entity) []ecs.Entity {
|
func FindCarriedUnder(who ecs.Entity) []ecs.Entity {
|
||||||
coords := Controller.GetComponent(who, ecs.CoordsComponent).(types.Coords)
|
pickerCoords := Controller.GetComponent(who, ecs.CoordsComponent).(types.Coords)
|
||||||
carrieds := Controller.GetEntitiesWithComponent(ecs.CarriedComponent)
|
// _И_ носимые _И_ имеющие координаты, т.е. где-то лежащие
|
||||||
|
carrieds := Controller.GetEntitiesWithComponent(ecs.CarriedComponent, ecs.CoordsComponent)
|
||||||
result := make([]ecs.Entity, 0)
|
result := make([]ecs.Entity, 0)
|
||||||
for _, ent := range carrieds {
|
for _, carried := range carrieds {
|
||||||
car := Controller.GetComponent(ent, ecs.CoordsComponent)
|
carriedCoords := Controller.GetComponent(carried, ecs.CoordsComponent).(types.Coords)
|
||||||
if car == coords {
|
if pickerCoords.IsAdjacentTo(&carriedCoords) {
|
||||||
result = append(result, ent)
|
result = append(result, carried)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package itemprops
|
package itemprops
|
||||||
|
|
||||||
|
import "github.com/shopspring/decimal"
|
||||||
|
|
||||||
//MedicalSystem организм
|
//MedicalSystem организм
|
||||||
// Humanoid
|
// Humanoid
|
||||||
// Circuits
|
// Circuits
|
||||||
@ -55,94 +57,95 @@ package itemprops
|
|||||||
// -> [right] joint -> leg -> joint -> hip -> joint -> foot -> 5 x finger
|
// -> [right] joint -> leg -> joint -> hip -> joint -> foot -> 5 x finger
|
||||||
// -> head -> joint -> jaw
|
// -> head -> joint -> jaw
|
||||||
|
|
||||||
//MedicalSystem Организм
|
// MedicalSystem Организм
|
||||||
type MedicalSystem struct {
|
type MedicalSystem struct {
|
||||||
BasePart BodyPart
|
BasePart BodyPart
|
||||||
}
|
}
|
||||||
|
|
||||||
//MedicalCircuit Система обращения
|
// MedicalCircuit Система обращения
|
||||||
type MedicalCircuit struct {
|
type MedicalCircuit struct {
|
||||||
Provides MedicalAbility
|
Provides MedicalAbility
|
||||||
DependsOn Organ
|
DependsOn Organ
|
||||||
Vessel MedicalVessel
|
Vessel MedicalVessel
|
||||||
Contains []Organ
|
Contains []Organ
|
||||||
}
|
}
|
||||||
|
|
||||||
//MedicalVessel кровь, желчь, пульпа, воздух, еда
|
// MedicalVessel кровь, желчь, пульпа, воздух, еда
|
||||||
type MedicalVessel struct {
|
type MedicalVessel struct {
|
||||||
Name string
|
Name string
|
||||||
Material
|
Material
|
||||||
Pressure DimensionItemDensity
|
Pressure decimal.Decimal //Pressure давление, kg / m3
|
||||||
}
|
}
|
||||||
|
|
||||||
//BodyPart часть тела
|
// BodyPart часть тела
|
||||||
type BodyPart struct {
|
type BodyPart struct {
|
||||||
LayerExtra MedicalMaterial
|
LayerExtra MedicalMaterial
|
||||||
LayerOuter MedicalMaterial
|
LayerOuter MedicalMaterial
|
||||||
LayerMiddle MedicalMaterial
|
LayerMiddle MedicalMaterial
|
||||||
LayerInner MedicalMaterial
|
LayerInner MedicalMaterial
|
||||||
|
|
||||||
Joints []Joint
|
Size DimensionItemSize
|
||||||
Contains []InnerOrgan
|
Joints []Joint
|
||||||
Exposes []OuterOrgan
|
Contains []InnerOrgan
|
||||||
|
Exposes []OuterOrgan
|
||||||
}
|
}
|
||||||
|
|
||||||
//Joint суставы, к чему и что крепится
|
// Joint суставы, к чему и что крепится
|
||||||
type Joint struct {
|
type Joint struct {
|
||||||
Name string
|
Name string
|
||||||
ConnectsFrom BodyPart
|
ConnectsFrom BodyPart
|
||||||
ConnectsTo BodyPart
|
ConnectsTo BodyPart
|
||||||
}
|
}
|
||||||
|
|
||||||
type Organ struct {
|
type Organ struct {
|
||||||
Name string
|
Name string
|
||||||
Material
|
Material
|
||||||
}
|
}
|
||||||
|
|
||||||
//InnerOrgan ливер, селезёнка, сердце, кишки итп
|
// InnerOrgan ливер, селезёнка, сердце, кишки итп
|
||||||
type InnerOrgan struct {
|
type InnerOrgan struct {
|
||||||
Organ
|
Organ
|
||||||
DependsOn MedicalCircuit
|
DependsOn MedicalCircuit
|
||||||
BelongsTo MedicalCircuit
|
BelongsTo MedicalCircuit
|
||||||
}
|
}
|
||||||
|
|
||||||
//OuterOrgan глаза, уши, волосы, когти итп
|
// OuterOrgan глаза, уши, волосы, когти итп
|
||||||
type OuterOrgan struct {
|
type OuterOrgan struct {
|
||||||
Organ
|
Organ
|
||||||
DependsOn MedicalCircuit
|
DependsOn MedicalCircuit
|
||||||
BelongsTo MedicalCircuit
|
BelongsTo MedicalCircuit
|
||||||
}
|
}
|
||||||
|
|
||||||
//слой части тела - кожа/чешуя/роговые пластины/хитиновый панцирь, жир, мускулы, кости
|
// слой части тела - кожа/чешуя/роговые пластины/хитиновый панцирь, жир, мускулы, кости
|
||||||
type MedicalMaterial struct {
|
type MedicalMaterial struct {
|
||||||
Name string
|
Name string
|
||||||
Material
|
Material
|
||||||
MedicalSystemFlags
|
MedicalSystemFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
//@todo заменить на Medical Circuit
|
// @todo заменить на Medical Circuit
|
||||||
type MedicalSystemFlags struct {
|
type MedicalSystemFlags struct {
|
||||||
//Structural является ли опорным аппаратом
|
//Structural является ли опорным аппаратом
|
||||||
Structural bool
|
Structural bool
|
||||||
//Содежит ли кровь/ихор/
|
//Содежит ли кровь/ихор/
|
||||||
MajorVeins bool //вход на мотор, сломаешь - быстро выйдет из строя если будет двигаться
|
MajorVeins bool //вход на мотор, сломаешь - быстро выйдет из строя если будет двигаться
|
||||||
MajorArteria bool //выход, то же самое + высокое давление
|
MajorArteria bool //выход, то же самое + высокое давление
|
||||||
|
|
||||||
Veins bool //вход на мотор
|
Veins bool //вход на мотор
|
||||||
Arteria bool //выход из мотора, высокое давление
|
Arteria bool //выход из мотора, высокое давление
|
||||||
|
|
||||||
MajorNerve bool //повредишь - ниже по суставам не работает
|
MajorNerve bool //повредишь - ниже по суставам не работает
|
||||||
NerveTissue bool //повредишь - ниже по суставамс болит
|
NerveTissue bool //повредишь - ниже по суставамс болит
|
||||||
|
|
||||||
OxygenTube bool //трахея
|
OxygenTube bool //трахея
|
||||||
OxygenPump bool //лёгкое
|
OxygenPump bool //лёгкое
|
||||||
|
|
||||||
BloodPump bool //мотор
|
BloodPump bool //мотор
|
||||||
|
|
||||||
ContainsCongestionLiquid bool
|
ContainsCongestionLiquid bool
|
||||||
|
|
||||||
IsMainCongestionPump bool
|
IsMainCongestionPump bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//MedicalAbility спсобность есть, стоять, не терять равновесие, дышать, выздоравливать, лечить свои органы, видеть итп
|
// MedicalAbility спсобность есть, стоять, не терять равновесие, дышать, выздоравливать, лечить свои органы, видеть итп
|
||||||
type MedicalAbility string
|
type MedicalAbility string
|
||||||
|
215
engine/items/itemprops/ip_test.go
Normal file
215
engine/items/itemprops/ip_test.go
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
package itemprops
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IpTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
// метод для установки тестовых данных для всего набора, запускается до всего прочего
|
||||||
|
func (suite *IpTestSuite) SetupSuite() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// метод для сноса наделанного тестом до идеально чистого состояния, запускается после всего прочего
|
||||||
|
func (suite *IpTestSuite) TearDownSuite() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// запускается перед каждым тестом
|
||||||
|
func (suite *IpTestSuite) SetupTest() {}
|
||||||
|
|
||||||
|
// запускается после каждого теста
|
||||||
|
func (suite *IpTestSuite) TearDownTest() {}
|
||||||
|
|
||||||
|
func TestApi(t *testing.T) {
|
||||||
|
tests := new(IpTestSuite)
|
||||||
|
suite.Run(t, tests)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *IpTestSuite) TestMaterialWeightAndVolume() {
|
||||||
|
// плотность https://tekkos.ru/katalog/poleznaya-informatsiya/tablica-plotnosti-stali-kg-m3.html
|
||||||
|
// ударная вязкость https://nposanef.ru/DOCUMENTS/PB-03-605-03/PB-03-605-03_Tab-2.6.pdf
|
||||||
|
// температура плавления http://zaozmi.ru/polezno/temperatura_plavleniya_metallov.html
|
||||||
|
// температура кипения http://temperatures.ru/pages/temperatura_plavleniya_i_kipeniya
|
||||||
|
// Пределы прочности некоторых материалов https://sevparitet.ru/raznoe/koefficient-uprugosti-tablica.html
|
||||||
|
|
||||||
|
metalMaterialFlags := MaterialFlags{
|
||||||
|
ConductsElictricity: true,
|
||||||
|
BlocksLiquid: true,
|
||||||
|
AcidResistant: true,
|
||||||
|
BlocksGas: true,
|
||||||
|
Flammable: false,
|
||||||
|
ConductsHeat: true,
|
||||||
|
Radiates: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
woodMaterialFlags := MaterialFlags{
|
||||||
|
ConductsElictricity: false,
|
||||||
|
BlocksLiquid: true,
|
||||||
|
AcidResistant: false,
|
||||||
|
BlocksGas: true,
|
||||||
|
Flammable: true,
|
||||||
|
ConductsHeat: false,
|
||||||
|
Radiates: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
teststeel := Material{
|
||||||
|
Id: "teststeel",
|
||||||
|
Name: "steel",
|
||||||
|
Flags: metalMaterialFlags,
|
||||||
|
Density: DimensionItemDensity{decimal.NewFromInt(7800)},
|
||||||
|
FractureToughness: DimensionFractureToughness{decimal.NewFromInt(30)},
|
||||||
|
MeltingPoint: DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(1400), Valid: true}},
|
||||||
|
BoilingPoint: DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(3200), Valid: true}},
|
||||||
|
}
|
||||||
|
|
||||||
|
testOakWood := Material{
|
||||||
|
Id: "testoakwood",
|
||||||
|
Name: "oakwood",
|
||||||
|
Flags: woodMaterialFlags,
|
||||||
|
Density: DimensionItemDensity{decimal.NewFromInt(700)},
|
||||||
|
FractureToughness: DimensionFractureToughness{decimal.NewFromFloat(4.5)},
|
||||||
|
MeltingPoint: DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(600), Valid: true}}, //загорается при 600 град Цельсия
|
||||||
|
}
|
||||||
|
|
||||||
|
testCube := ItemPhysics{
|
||||||
|
Material: teststeel,
|
||||||
|
DimensionItemRigidity: DimensionItemRigidity{decimal.NewFromInt(65)},
|
||||||
|
DimensionItemSize: DimensionItemSize{
|
||||||
|
Width: decimal.NewFromFloat(0.1),
|
||||||
|
Height: decimal.NewFromFloat(0.1),
|
||||||
|
Depth: decimal.NewNullDecimal(decimal.NewFromFloat(0.1)),
|
||||||
|
Thickness: decimal.NullDecimal{},
|
||||||
|
},
|
||||||
|
DimensionItemTemperature: DimensionItemTemperature{decimal.NewFromInt(20)},
|
||||||
|
}
|
||||||
|
|
||||||
|
suite.Equal(decimal.NewFromFloat(7.8).String(), testCube.Weight().String())
|
||||||
|
suite.Equal(decimal.NewFromFloat(0.001).String(), testCube.Volume().String())
|
||||||
|
|
||||||
|
testOakCube := ItemPhysics{
|
||||||
|
Material: testOakWood,
|
||||||
|
DimensionItemRigidity: DimensionItemRigidity{decimal.NewFromInt(4)},
|
||||||
|
DimensionItemSize: DimensionItemSize{
|
||||||
|
Width: decimal.NewFromFloat(0.1),
|
||||||
|
Height: decimal.NewFromFloat(0.1),
|
||||||
|
Depth: decimal.NewNullDecimal(decimal.NewFromFloat(0.1)),
|
||||||
|
Thickness: decimal.NullDecimal{},
|
||||||
|
},
|
||||||
|
DimensionItemTemperature: DimensionItemTemperature{decimal.NewFromInt(20)},
|
||||||
|
}
|
||||||
|
|
||||||
|
//oakwood is ~10 times lighter than steel
|
||||||
|
suite.Equal(decimal.NewFromFloat(0.7).String(), testOakCube.Weight().String())
|
||||||
|
suite.Equal(decimal.NewFromFloat(0.001).String(), testOakCube.Volume().String())
|
||||||
|
|
||||||
|
testCuirass := ItemPhysics{
|
||||||
|
Material: teststeel,
|
||||||
|
DimensionItemRigidity: DimensionItemRigidity{decimal.NewFromInt(55)},
|
||||||
|
DimensionItemSize: DimensionItemSize{
|
||||||
|
Width: decimal.NewFromFloat(0.5), //60 cm wide
|
||||||
|
Height: decimal.NewFromFloat(0.8), //80 cm high
|
||||||
|
Depth: decimal.NewNullDecimal(decimal.NewFromFloat(0.4)), //50 cm deep
|
||||||
|
Thickness: decimal.NewNullDecimal(decimal.NewFromFloat(0.001)), // 1mm thick
|
||||||
|
},
|
||||||
|
DimensionItemTemperature: DimensionItemTemperature{},
|
||||||
|
}
|
||||||
|
|
||||||
|
//12.1992 kg HEAVY ARMOR IS HEAVY
|
||||||
|
suite.Equal(decimal.NewFromFloat(12.1992).String(), testCuirass.Weight().String())
|
||||||
|
//0.001564 m3 of steel
|
||||||
|
suite.Equal(decimal.NewFromFloat(0.001564).String(), testCuirass.Volume().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *IpTestSuite) TestMaterialSerialization() {
|
||||||
|
metalMaterialFlags := MaterialFlags{
|
||||||
|
ConductsElictricity: true,
|
||||||
|
BlocksLiquid: true,
|
||||||
|
AcidResistant: true,
|
||||||
|
BlocksGas: true,
|
||||||
|
Flammable: false,
|
||||||
|
ConductsHeat: true,
|
||||||
|
Radiates: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
woodMaterialFlags := MaterialFlags{
|
||||||
|
ConductsElictricity: false,
|
||||||
|
BlocksLiquid: true,
|
||||||
|
AcidResistant: false,
|
||||||
|
BlocksGas: true,
|
||||||
|
Flammable: true,
|
||||||
|
ConductsHeat: false,
|
||||||
|
Radiates: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
teststeel := Material{
|
||||||
|
Id: "teststeel",
|
||||||
|
Name: "steel",
|
||||||
|
Flags: metalMaterialFlags,
|
||||||
|
Density: DimensionItemDensity{decimal.NewFromInt(7800)},
|
||||||
|
FractureToughness: DimensionFractureToughness{decimal.NewFromInt(30)},
|
||||||
|
MeltingPoint: DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(1400), Valid: true}},
|
||||||
|
BoilingPoint: DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(3200), Valid: true}},
|
||||||
|
}
|
||||||
|
|
||||||
|
testOakWood := Material{
|
||||||
|
Id: "testoakwood",
|
||||||
|
Name: "oakwood",
|
||||||
|
Flags: woodMaterialFlags,
|
||||||
|
Density: DimensionItemDensity{decimal.NewFromInt(700)},
|
||||||
|
FractureToughness: DimensionFractureToughness{decimal.NewFromFloat(4.5)},
|
||||||
|
MeltingPoint: DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(600), Valid: true}}, //загорается при 600 град Цельсия
|
||||||
|
}
|
||||||
|
bytes, err := json.Marshal(teststeel)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.Equal(
|
||||||
|
`{"id":"teststeel","name":"steel","material_flags":{"conducts_elictricity":true,"blocks_liquid":true,"acid_resistant":true,"blocks_gas":true,"flammable":false,"conducts_heat":true,"radiates":true},"density":"7800","fracture_toughness":"30","melting_point":"1400","boiling_point":"3200"}`,
|
||||||
|
string(bytes),
|
||||||
|
)
|
||||||
|
|
||||||
|
bytes, err = json.Marshal(testOakWood)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.Equal(`{"id":"testoakwood","name":"oakwood","material_flags":{"conducts_elictricity":false,"blocks_liquid":true,"acid_resistant":false,"blocks_gas":true,"flammable":true,"conducts_heat":false,"radiates":false},"density":"700","fracture_toughness":"4.5","melting_point":"600","boiling_point":null}`,
|
||||||
|
string(bytes),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *IpTestSuite) TestMaterialDeserialization() {
|
||||||
|
|
||||||
|
logger := log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339})
|
||||||
|
mm, err := NewMaterialMap("../../..", logger)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
metalMaterialFlags := MaterialFlags{
|
||||||
|
ConductsElictricity: true,
|
||||||
|
BlocksLiquid: true,
|
||||||
|
AcidResistant: true,
|
||||||
|
BlocksGas: true,
|
||||||
|
Flammable: false,
|
||||||
|
ConductsHeat: true,
|
||||||
|
Radiates: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
teststeel := Material{
|
||||||
|
Id: "steel",
|
||||||
|
Name: "steel",
|
||||||
|
Flags: metalMaterialFlags,
|
||||||
|
Density: DimensionItemDensity{decimal.NewFromInt(7800)},
|
||||||
|
FractureToughness: DimensionFractureToughness{decimal.NewFromInt(30)},
|
||||||
|
MeltingPoint: DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(1400), Valid: true}},
|
||||||
|
BoilingPoint: DimensionItemNullTemperature{decimal.NullDecimal{Decimal: decimal.NewFromInt(3200), Valid: true}},
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedsteel := mm["steel"]
|
||||||
|
suite.Equalf(teststeel, *loadedsteel, "error: %s")
|
||||||
|
_ = mm
|
||||||
|
}
|
@ -3,35 +3,54 @@ package itemprops
|
|||||||
import "github.com/shopspring/decimal"
|
import "github.com/shopspring/decimal"
|
||||||
|
|
||||||
type ItemPhysics struct {
|
type ItemPhysics struct {
|
||||||
Material Material
|
Material `json:"material"`
|
||||||
Rigidity DimensionItemRigidity
|
//DimensionItemRigidity жёсткость (самого предмета а не материала), мера прочности,
|
||||||
Size DimensionItemSize
|
//уменьшается со временем, может зависеть от тепмературы
|
||||||
Temperature DimensionItemTemperature
|
DimensionItemRigidity `json:"rigidity"`
|
||||||
|
DimensionItemSize `json:"size"`
|
||||||
|
DimensionItemTemperature `json:"temperature"`
|
||||||
|
//CubeFactor фактор близости куб <-> сфера по площади поверхности, чем ближе к 0, тем ближе к сфере,
|
||||||
|
//100 - куб, >100 - для суперсложных (шипастых например) поверхностей
|
||||||
|
CubeFactor decimal.NullDecimal `json:"cube_factor,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//DimensionItemSize length in m (1 mm = 1/1000 of 1m)
|
// DimensionItemSize length in m (1 mm = 1/1000 of 1m)
|
||||||
type DimensionItemSize struct {
|
type DimensionItemSize struct {
|
||||||
Width decimal.Decimal
|
Width decimal.Decimal `json:"width"`
|
||||||
Height decimal.Decimal
|
Height decimal.Decimal `json:"height"`
|
||||||
// if item is solid - depth in m (1mm = 1/1000 of m)
|
// if item is solid - depth in m (1mm = 1/1000 of m)
|
||||||
Depth decimal.NullDecimal
|
Depth decimal.NullDecimal `json:"depth,omitempty"`
|
||||||
//Thickness if item is hollow - thickness of outer item shell, ie for armor, in m (1 mm = 1/1000 of m)
|
//Thickness if item is hollow - thickness of outer item shell, ie for armor, in m (1 mm = 1/1000 of m)
|
||||||
Thickness decimal.NullDecimal
|
Thickness decimal.NullDecimal `json:"thickness,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//Area is frontal area
|
// Area is frontal area
|
||||||
func (d *DimensionItemSize) Area() decimal.Decimal {
|
func (d *DimensionItemSize) Area() decimal.Decimal {
|
||||||
return d.Width.Mul(d.Height)
|
return d.Width.Mul(d.Height)
|
||||||
}
|
}
|
||||||
|
|
||||||
//DimensionItemDensity density in kg/m3
|
func (ip *ItemPhysics) Weight() decimal.Decimal {
|
||||||
type DimensionItemDensity decimal.Decimal
|
return ip.Material.Density.Mul(ip.Volume())
|
||||||
|
}
|
||||||
|
|
||||||
//DimensionItemRigidity rigidity жёсткость, способность твёрдого тела, конструкции или её элементов сопротивляться деформации in N/m
|
func (d *ItemPhysics) Volume() decimal.Decimal {
|
||||||
type DimensionItemRigidity decimal.Decimal
|
v := d.Width.Mul(d.Height)
|
||||||
|
//есть глубина
|
||||||
//NotchFractureToughness ударная вязкость по Шарпи, Дж (надо ли?)
|
if !d.Depth.Decimal.IsZero() {
|
||||||
type NotchFractureToughness decimal.Decimal
|
v = v.Mul(d.Depth.Decimal)
|
||||||
|
//пустотелый
|
||||||
//DimensionItemTemperature in celsius, -273 to 10000
|
if !d.Thickness.Decimal.IsZero() {
|
||||||
type DimensionItemTemperature decimal.Decimal
|
surfaceArea := d.Width.Mul(d.Height).Mul(decimal.NewFromInt(2)).
|
||||||
|
Add(d.Height.Mul(d.Depth.Decimal).Mul(decimal.NewFromInt(2))).
|
||||||
|
Add(d.Width.Mul(d.Depth.Decimal).Mul(decimal.NewFromInt(2)))
|
||||||
|
surfaceAreaCoeff := 0.85
|
||||||
|
if !d.CubeFactor.Decimal.IsZero() {
|
||||||
|
surfaceAreaCoeff = surfaceAreaCoeff * float64(int(d.CubeFactor.Decimal.IntPart())/100)
|
||||||
|
}
|
||||||
|
v = surfaceArea.Mul(d.Thickness.Decimal).
|
||||||
|
//волюнтаристский коэффт отличия поверхности от куба, см https/en.wikipedia.org/wiki/Volume-to-surface_area_ratio
|
||||||
|
Mul(decimal.NewFromFloat(surfaceAreaCoeff))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
35
engine/items/itemprops/item_physics_dimensions.go
Normal file
35
engine/items/itemprops/item_physics_dimensions.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package itemprops
|
||||||
|
|
||||||
|
import "github.com/shopspring/decimal"
|
||||||
|
|
||||||
|
// плотность https://tekkos.ru/katalog/poleznaya-informatsiya/tablica-plotnosti-stali-kg-m3.html
|
||||||
|
// ударная вязкость https://nposanef.ru/DOCUMENTS/PB-03-605-03/PB-03-605-03_Tab-2.6.pdf
|
||||||
|
// температура плавления http://zaozmi.ru/polezno/temperatura_plavleniya_metallov.html
|
||||||
|
// температура кипения http://temperatures.ru/pages/temperatura_plavleniya_i_kipeniya
|
||||||
|
// Пределы прочности некоторых материалов https://sevparitet.ru/raznoe/koefficient-uprugosti-tablica.html
|
||||||
|
|
||||||
|
// DimensionItemDensity density in kg/m3
|
||||||
|
type DimensionItemDensity struct {
|
||||||
|
decimal.Decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
// DimensionItemRigidity rigidity жёсткость, способность твёрдого тела, конструкции или её элементов сопротивляться деформации in N/m
|
||||||
|
type DimensionItemRigidity struct {
|
||||||
|
decimal.Decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
// DimensionFractureToughness ударная вязкость по Шарпи, Дж (надо ли?)
|
||||||
|
// Ударная вязкость, мера скорости поглощения энергии без деформаций, джоули на квадратный метр в секунду
|
||||||
|
type DimensionFractureToughness struct {
|
||||||
|
decimal.Decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
// DimensionItemTemperature in celsius, -273 to 10000
|
||||||
|
type DimensionItemTemperature struct {
|
||||||
|
decimal.Decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
// DimensionItemTemperature in celsius, -273 to 10000
|
||||||
|
type DimensionItemNullTemperature struct {
|
||||||
|
decimal.NullDecimal
|
||||||
|
}
|
@ -1,20 +1,117 @@
|
|||||||
package itemprops
|
package itemprops
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
type Material struct {
|
type Material struct {
|
||||||
Name string
|
Id string `json:"id"`
|
||||||
Flags MaterialFlags
|
Name string `json:"name"`
|
||||||
Density DimensionItemDensity
|
Flags MaterialFlags `json:"material_flags"`
|
||||||
FractureToughness NotchFractureToughness
|
Density DimensionItemDensity `json:"density"`
|
||||||
MeltingPoint DimensionItemTemperature
|
FractureToughness DimensionFractureToughness `json:"fracture_toughness"`
|
||||||
BoilingPoint DimensionItemTemperature
|
MeltingPoint DimensionItemNullTemperature `json:"melting_point,omitempty"`
|
||||||
|
BoilingPoint DimensionItemNullTemperature `json:"boiling_point,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m Material) Unmarshal() {}
|
||||||
|
|
||||||
type MaterialFlags struct {
|
type MaterialFlags struct {
|
||||||
ConductsElictricity bool
|
ConductsElictricity bool `json:"conducts_elictricity"`
|
||||||
BlocksLiquid bool
|
BlocksLiquid bool `json:"blocks_liquid"`
|
||||||
AcidResistant bool
|
AcidResistant bool `json:"acid_resistant"`
|
||||||
BlocksGas bool
|
BlocksGas bool `json:"blocks_gas"`
|
||||||
Flammable bool
|
Flammable bool `json:"flammable"`
|
||||||
ConductsHeat bool
|
ConductsHeat bool `json:"conducts_heat"`
|
||||||
Radiates bool
|
Radiates bool `json:"radiates"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MaterialMap map[string]*Material
|
||||||
|
|
||||||
|
type tt map[string]MaterialMap
|
||||||
|
|
||||||
|
func NewMaterialMap(path string, logger zerolog.Logger) (MaterialMap, error) {
|
||||||
|
|
||||||
|
mm := make(MaterialMap)
|
||||||
|
tmp := make(map[string][]interface{})
|
||||||
|
flags := make(map[string]*MaterialFlags)
|
||||||
|
err := filepath.Walk(path+"/assets/materials",
|
||||||
|
func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(path, ".json") {
|
||||||
|
splt := strings.Split(path, "/")
|
||||||
|
logger.Info().Msgf("loading %s %d", splt[len(splt)-1], info.Size())
|
||||||
|
bytes, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ttmp := make(map[string][]interface{})
|
||||||
|
err = json.Unmarshal(bytes, &ttmp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for idx := range ttmp {
|
||||||
|
tmp[idx] = append(tmp[idx], ttmp[idx]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
_ = flags
|
||||||
|
if lst, ok := tmp["material_flags"]; ok {
|
||||||
|
for _, item := range lst {
|
||||||
|
ttt := item.(map[string]interface{})
|
||||||
|
_ = ttt
|
||||||
|
for clause, item2 := range ttt {
|
||||||
|
bts, err := json.Marshal(item2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not marshal back:%w", err)
|
||||||
|
}
|
||||||
|
flags[clause] = &MaterialFlags{}
|
||||||
|
err = json.Unmarshal(bts, flags[clause])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not unmarshal to material_flags:%w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Info().Msgf("loaded %d material flag sets", len(flags))
|
||||||
|
|
||||||
|
if lst, ok := tmp["materials"]; ok {
|
||||||
|
for _, item := range lst {
|
||||||
|
ttt := item.(map[string]interface{})
|
||||||
|
_ = ttt
|
||||||
|
for clause, item2 := range ttt {
|
||||||
|
|
||||||
|
toReplace := item2.(map[string]interface{})["material_flags"]
|
||||||
|
|
||||||
|
//todo generalize
|
||||||
|
if ref, ok := toReplace.(map[string]interface{})["$ref"]; ok {
|
||||||
|
rfs := strings.Split(ref.(string), "/")
|
||||||
|
referredFlag := rfs[len(rfs)-1]
|
||||||
|
item2.(map[string]interface{})["material_flags"] = flags[referredFlag]
|
||||||
|
}
|
||||||
|
bts, err := json.Marshal(item2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not marshal back:%w", err)
|
||||||
|
}
|
||||||
|
mm[clause] = &Material{Id: clause}
|
||||||
|
err = json.Unmarshal(bts, mm[clause])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not unmarshal to material_flags:%w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mm, err
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func (ms MatterState) Change(from MatterState, to MatterState) bool {
|
|||||||
return false
|
return false
|
||||||
}(transitions[from], to)
|
}(transitions[from], to)
|
||||||
if !newStateFound {
|
if !newStateFound {
|
||||||
log.Warn().Msgf("Transition %s -> %s is impossible", from, to)
|
log.Warn().Msgf(`Transition %d -> %d is impossible`, from, to)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// check temperatures/conditions, see template
|
// check temperatures/conditions, see template
|
||||||
|
@ -23,11 +23,11 @@ func (mov Moveable) Walk() {
|
|||||||
|
|
||||||
//fixme change it to WhatsOnTile
|
//fixme change it to WhatsOnTile
|
||||||
func (mov Moveable) IsBlocked(c types.Coords) bool {
|
func (mov Moveable) IsBlocked(c types.Coords) bool {
|
||||||
if mov.Level.GetTile(c).BlocksPass == true {
|
if mov.Level.GetTile(c).BlocksPass {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
list := mov.Controller.GetEntitiesWithComponent(ecs.MobComponent)
|
list := mov.Controller.GetEntitiesWithComponent(ecs.MobComponent)
|
||||||
for idx, _ := range list {
|
for idx := range list {
|
||||||
coords := mov.Controller.GetComponent(list[idx], ecs.CoordsComponent)
|
coords := mov.Controller.GetComponent(list[idx], ecs.CoordsComponent)
|
||||||
if coords == nil {
|
if coords == nil {
|
||||||
continue
|
continue
|
||||||
@ -50,7 +50,7 @@ func (mov Moveable) IsBlocked(c types.Coords) bool {
|
|||||||
func Walk(entity ecs.Entity, state *gamestate.GameState, dx, dy int) {
|
func Walk(entity ecs.Entity, state *gamestate.GameState, dx, dy int) {
|
||||||
controller := state.Controller
|
controller := state.Controller
|
||||||
coords := controller.GetComponent(state.Player, ecs.CoordsComponent).(types.Coords)
|
coords := controller.GetComponent(state.Player, ecs.CoordsComponent).(types.Coords)
|
||||||
newCoords := types.Coords{coords.X + dx, coords.Y + dy}
|
newCoords := types.Coords{X: coords.X + dx, Y: coords.Y + dy}
|
||||||
if !state.Level.InBounds(newCoords) {
|
if !state.Level.InBounds(newCoords) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package screens
|
package screens
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/effects"
|
"strings"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
|
"lab.zaar.be/thefish/alchemyst-go/effects"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
"strings"
|
"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DevmenuScreen struct {
|
type DevmenuScreen struct {
|
||||||
@ -69,7 +70,7 @@ func (devm *DevmenuScreen) HandleInput(input string) {
|
|||||||
level.Tiles[idx].Visible = true
|
level.Tiles[idx].Visible = true
|
||||||
level.Tiles[idx].Explored = true
|
level.Tiles[idx].Explored = true
|
||||||
}
|
}
|
||||||
appctx.Logger(devm.ctx).Warn().Msg("making everything visible!")
|
appctx.Logger().Warn().Msg("making everything visible!")
|
||||||
devm.scm.SetScreen(devm.scm.PreviousScreen)
|
devm.scm.SetScreen(devm.scm.PreviousScreen)
|
||||||
break
|
break
|
||||||
case "p":
|
case "p":
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package screens
|
package screens
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/ecs/systems"
|
"lab.zaar.be/thefish/alchemyst-go/engine/ecs/systems"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/fov"
|
"lab.zaar.be/thefish/alchemyst-go/engine/fov"
|
||||||
@ -15,7 +14,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GameScreen struct {
|
type GameScreen struct {
|
||||||
ctx context.Context
|
|
||||||
mw *mainwindow.MainWindow
|
mw *mainwindow.MainWindow
|
||||||
state *gamestate.GameState
|
state *gamestate.GameState
|
||||||
vp *mainwindow.ViewPort
|
vp *mainwindow.ViewPort
|
||||||
@ -24,9 +22,8 @@ type GameScreen struct {
|
|||||||
fov fov.Fov
|
fov fov.Fov
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGameScreen(ctx context.Context, mw *mainwindow.MainWindow, state *gamestate.GameState, viewPort *mainwindow.ViewPort, controller *ecs.Controller, scm *types.ScreenManager) *GameScreen {
|
func NewGameScreen(mw *mainwindow.MainWindow, state *gamestate.GameState, viewPort *mainwindow.ViewPort, controller *ecs.Controller, scm *types.ScreenManager) *GameScreen {
|
||||||
ts := &GameScreen{
|
ts := &GameScreen{
|
||||||
ctx: ctx,
|
|
||||||
mw: mw,
|
mw: mw,
|
||||||
state: state,
|
state: state,
|
||||||
vp: viewPort,
|
vp: viewPort,
|
||||||
@ -49,7 +46,7 @@ func (ts *GameScreen) UseEcs() bool { return true }
|
|||||||
func (ts *GameScreen) Enter() {
|
func (ts *GameScreen) Enter() {
|
||||||
ts.mw.GetLayer("overlay").ClearArea(0, ts.mw.H-3, 30, 3)
|
ts.mw.GetLayer("overlay").ClearArea(0, ts.mw.H-3, 30, 3)
|
||||||
ts.mw.GetLayer("overlay").WithColor("#77777777").
|
ts.mw.GetLayer("overlay").WithColor("#77777777").
|
||||||
Print(1, ts.mw.H-2, "Press [color=white]?[/color] for help")
|
Print(ts.mw.W - 17 , 1, "Press [color=white]?[/color] for help")
|
||||||
}
|
}
|
||||||
func (ts *GameScreen) Exit() {
|
func (ts *GameScreen) Exit() {
|
||||||
//trs := ts.controller.GetSystem(ecs.LevelRenderSystem)
|
//trs := ts.controller.GetSystem(ecs.LevelRenderSystem)
|
||||||
@ -58,6 +55,7 @@ func (ts *GameScreen) Exit() {
|
|||||||
//remove what we dont need
|
//remove what we dont need
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fixme kry names to action constants!
|
||||||
func (ts *GameScreen) HandleInput(input string) {
|
func (ts *GameScreen) HandleInput(input string) {
|
||||||
//ts.state.Do(func(){
|
//ts.state.Do(func(){
|
||||||
switch input {
|
switch input {
|
||||||
@ -100,13 +98,22 @@ func (ts *GameScreen) HandleInput(input string) {
|
|||||||
} //do nothing
|
} //do nothing
|
||||||
//select if there is more than 1
|
//select if there is more than 1
|
||||||
if len(carrieds) > 1 {
|
if len(carrieds) > 1 {
|
||||||
appctx.Logger(ts.ctx).Warn().Msg("Passing item list to inventory not implemented yet")
|
appctx.Logger().Warn().Msg("Passing item list to inventory not implemented yet")
|
||||||
} else {
|
} else {
|
||||||
//call pickup in selected
|
//call pickup in selected
|
||||||
cc := items.Controller.GetComponent(carrieds[0], ecs.CarriedComponent).(items.Carried)
|
cc := items.Controller.GetComponent(carrieds[0], ecs.CarriedComponent).(items.Carried)
|
||||||
items.Carried.Pickup(cc, ts.state.Player, carrieds[0])
|
err := items.Carried.Pickup(cc, ts.state.Player, carrieds[0])
|
||||||
}
|
if err != nil {
|
||||||
|
// Message with error
|
||||||
|
//gameLog.Log.Error(err)
|
||||||
|
//@fixme!
|
||||||
|
appctx.Logger().Warn().Err(err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//log picked up
|
||||||
|
//gameLog.Log.Message(err)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "i":
|
case "i":
|
||||||
|
@ -63,6 +63,8 @@ func (is *InventoryScreen) Enter() {
|
|||||||
is.prepared.Prepare(is)
|
is.prepared.Prepare(is)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fixme key names to action constants!
|
||||||
|
//fixme unify scrolling controls!
|
||||||
func (is *InventoryScreen) HandleInput(input string) {
|
func (is *InventoryScreen) HandleInput(input string) {
|
||||||
if strings.Contains(string(runeIndex), strings.Replace(input, "Shift+", "", -1)) {
|
if strings.Contains(string(runeIndex), strings.Replace(input, "Shift+", "", -1)) {
|
||||||
if strings.Contains("Shift+", input) {
|
if strings.Contains("Shift+", input) {
|
||||||
@ -76,7 +78,7 @@ func (is *InventoryScreen) HandleInput(input string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch input {
|
switch input {
|
||||||
case "Up":
|
case "Up", "k":
|
||||||
is.cursor = is.cursor - 1
|
is.cursor = is.cursor - 1
|
||||||
if is.cursor < 0 {
|
if is.cursor < 0 {
|
||||||
is.cursor = 0
|
is.cursor = 0
|
||||||
@ -88,7 +90,7 @@ func (is *InventoryScreen) HandleInput(input string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "Down":
|
case "Down", "j":
|
||||||
is.cursor = is.cursor + 1
|
is.cursor = is.cursor + 1
|
||||||
if is.cursor >= len(is.prepared) {
|
if is.cursor >= len(is.prepared) {
|
||||||
is.cursor = len(is.prepared) - 1
|
is.cursor = len(is.prepared) - 1
|
||||||
@ -119,7 +121,8 @@ func (is *InventoryScreen) HandleInput(input string) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "enter":
|
case "enter":
|
||||||
//select current under cursor
|
//show actions menu for item under cursor
|
||||||
|
//fixme implement
|
||||||
break;
|
break;
|
||||||
case "Escape":
|
case "Escape":
|
||||||
fallthrough
|
fallthrough
|
||||||
@ -143,7 +146,12 @@ func (is *InventoryScreen) InventoryRender() {
|
|||||||
footerHeight = footerHeight + 2
|
footerHeight = footerHeight + 2
|
||||||
}
|
}
|
||||||
_, headerHeight := menuLayer.PrintInside(is.Rect, is.header, blt.TK_ALIGN_LEFT)
|
_, headerHeight := menuLayer.PrintInside(is.Rect, is.header, blt.TK_ALIGN_LEFT)
|
||||||
itemField := types.Rect{is.X, is.Y + headerHeight + 1, is.W, is.H - headerHeight - footerHeight}
|
itemField := types.Rect{
|
||||||
|
X: is.X,
|
||||||
|
Y: is.Y + headerHeight + 1,
|
||||||
|
W: is.W,
|
||||||
|
H: is.H - headerHeight - footerHeight,
|
||||||
|
}
|
||||||
_ = itemField
|
_ = itemField
|
||||||
is.pageSize = itemField.H - 2
|
is.pageSize = itemField.H - 2
|
||||||
|
|
||||||
|
@ -1,166 +1,166 @@
|
|||||||
package screens
|
package screens
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
|
"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
|
||||||
blt "lab.zaar.be/thefish/bearlibterminal"
|
blt "lab.zaar.be/thefish/bearlibterminal"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const runeIndex = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
const runeIndex = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
type MenuScreen struct {
|
type MenuScreen struct {
|
||||||
types.Rect
|
types.Rect
|
||||||
|
|
||||||
mw *mainwindow.MainWindow
|
mw *mainwindow.MainWindow
|
||||||
scm *types.ScreenManager
|
scm *types.ScreenManager
|
||||||
renderParent bool
|
renderParent bool
|
||||||
|
|
||||||
items []interface{}
|
items []interface{}
|
||||||
offset int
|
offset int
|
||||||
|
|
||||||
drawFunc func()
|
drawFunc func()
|
||||||
inputFunc func(string)
|
inputFunc func(string)
|
||||||
|
|
||||||
title string
|
title string
|
||||||
header string
|
header string
|
||||||
footer string
|
footer string
|
||||||
redraw bool
|
redraw bool
|
||||||
bgColor string
|
bgColor string
|
||||||
fgColor string
|
fgColor string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMenuScreen(mw *mainwindow.MainWindow, scm *types.ScreenManager, title, header, footer string, rect types.Rect, renderParent bool) *MenuScreen {
|
func NewMenuScreen(mw *mainwindow.MainWindow, scm *types.ScreenManager, title, header, footer string, rect types.Rect, renderParent bool) *MenuScreen {
|
||||||
return &MenuScreen{
|
return &MenuScreen{
|
||||||
title: title,
|
title: title,
|
||||||
header: header,
|
header: header,
|
||||||
footer: footer,
|
footer: footer,
|
||||||
Rect: rect,
|
Rect: rect,
|
||||||
mw: mw,
|
mw: mw,
|
||||||
scm: scm,
|
scm: scm,
|
||||||
renderParent: renderParent,
|
renderParent: renderParent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) MakeList() *MenuScreen {
|
func (ms *MenuScreen) MakeList() *MenuScreen {
|
||||||
ms.drawFunc = ms.ListRender
|
ms.drawFunc = ms.ListRender
|
||||||
ms.inputFunc = ms.ListHandleInput
|
ms.inputFunc = ms.ListHandleInput
|
||||||
return ms
|
return ms
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) SetBgColor(color string) *MenuScreen {
|
func (ms *MenuScreen) SetBgColor(color string) *MenuScreen {
|
||||||
ms.bgColor = color
|
ms.bgColor = color
|
||||||
return ms
|
return ms
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) SetFgColor(color string) *MenuScreen {
|
func (ms *MenuScreen) SetFgColor(color string) *MenuScreen {
|
||||||
ms.fgColor = color
|
ms.fgColor = color
|
||||||
return ms
|
return ms
|
||||||
}
|
}
|
||||||
|
|
||||||
//fixme!!
|
//fixme!!
|
||||||
|
|
||||||
func (ms *MenuScreen) SetItems(items []interface{}) *MenuScreen {
|
func (ms *MenuScreen) SetItems(items []interface{}) *MenuScreen {
|
||||||
ms.items = items
|
ms.items = items
|
||||||
return ms
|
return ms
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) UseEcs() bool { return false }
|
func (ms *MenuScreen) UseEcs() bool { return false }
|
||||||
|
|
||||||
func (ms *MenuScreen) Enter() {
|
func (ms *MenuScreen) Enter() {
|
||||||
ms.redraw = true
|
ms.redraw = true
|
||||||
ms.offset = 0
|
ms.offset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) HandleInput(input string) {
|
func (ms *MenuScreen) HandleInput(input string) {
|
||||||
ms.inputFunc(input)
|
ms.inputFunc(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) Exit() {
|
func (ms *MenuScreen) Exit() {
|
||||||
menuLayer := ms.mw.GetLayer("menu")
|
menuLayer := ms.mw.GetLayer("menu")
|
||||||
menuLayer.ClearRect(ms.Rect)
|
menuLayer.ClearRect(ms.Rect)
|
||||||
bgLayer := ms.mw.GetLayer("menubg")
|
bgLayer := ms.mw.GetLayer("menubg")
|
||||||
bgLayer.ClearRect(ms.Rect)
|
bgLayer.ClearRect(ms.Rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) Render() {
|
func (ms *MenuScreen) Render() {
|
||||||
if ms.renderParent {
|
if ms.renderParent {
|
||||||
ms.scm.PreviousScreen.Render()
|
ms.scm.PreviousScreen.Render()
|
||||||
}
|
}
|
||||||
if (ms.redraw || ms.renderParent) {
|
if ms.redraw || ms.renderParent {
|
||||||
ms.redraw = false
|
ms.redraw = false
|
||||||
ms.drawFunc()
|
ms.drawFunc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) ListHandleInput(input string) {
|
func (ms *MenuScreen) ListHandleInput(input string) {
|
||||||
switch input {
|
switch input {
|
||||||
case "Up":
|
case "Up", "k":
|
||||||
ms.offset = ms.offset - 1
|
ms.offset = ms.offset - 1
|
||||||
if ms.offset < 0 {
|
if ms.offset < 0 {
|
||||||
ms.offset = 0
|
ms.offset = 0
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "Down":
|
case "Down", "j":
|
||||||
ms.offset = ms.offset + 1
|
ms.offset = ms.offset + 1
|
||||||
if ms.offset > len(ms.items)-1 {
|
if ms.offset > len(ms.items)-1 {
|
||||||
ms.offset = len(ms.items) - 1
|
ms.offset = len(ms.items) - 1
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "Escape":
|
case "Escape":
|
||||||
fallthrough
|
fallthrough
|
||||||
case "Space":
|
case "Space":
|
||||||
ms.scm.SetScreen(ms.scm.PreviousScreen)
|
ms.scm.SetScreen(ms.scm.PreviousScreen)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) ListRender() {
|
func (ms *MenuScreen) ListRender() {
|
||||||
menuLayer := ms.mw.GetLayer("menu")
|
menuLayer := ms.mw.GetLayer("menu")
|
||||||
menuLayer.ClearRect(ms.Rect)
|
menuLayer.ClearRect(ms.Rect)
|
||||||
bgLayer := ms.mw.GetLayer("menubg")
|
bgLayer := ms.mw.GetLayer("menubg")
|
||||||
bgLayer.ClearRect(ms.Rect)
|
bgLayer.ClearRect(ms.Rect)
|
||||||
bgLayer.WithColor(ms.bgColor).NewWindow(ms.Rect).Splash()
|
bgLayer.WithColor(ms.bgColor).NewWindow(ms.Rect).Splash()
|
||||||
menuLayer.WithColor(ms.fgColor).NewWindow(ms.Rect).DoubleBordered(ms.title)
|
menuLayer.WithColor(ms.fgColor).NewWindow(ms.Rect).DoubleBordered(ms.title)
|
||||||
menuLayer.Print(ms.X+(ms.W/2)-7, ms.Y+ms.H-1, "╡"+"[color=green]Space[/color] to close"+"╞")
|
menuLayer.Print(ms.X+(ms.W/2)-7, ms.Y+ms.H-1, "╡"+"[color=green]Space[/color] to close"+"╞")
|
||||||
footerHeight := 0
|
footerHeight := 0
|
||||||
if ms.footer != "" {
|
if ms.footer != "" {
|
||||||
_, footerHeight = menuLayer.PrintInside(ms.Rect, ms.footer, 9)
|
_, footerHeight = menuLayer.PrintInside(ms.Rect, ms.footer, 9)
|
||||||
footerHeight = footerHeight + 2
|
footerHeight = footerHeight + 2
|
||||||
}
|
}
|
||||||
_, headerHeight := menuLayer.PrintInside(ms.Rect, ms.header, blt.TK_ALIGN_LEFT)
|
_, headerHeight := menuLayer.PrintInside(ms.Rect, ms.header, blt.TK_ALIGN_LEFT)
|
||||||
itemField := types.Rect{ms.X, ms.Y + headerHeight + 1, ms.W, ms.H - headerHeight - footerHeight}
|
itemField := types.Rect{ms.X, ms.Y + headerHeight + 1, ms.W, ms.H - headerHeight - footerHeight}
|
||||||
_ = itemField
|
_ = itemField
|
||||||
var ilw, ilh int
|
var ilw, ilh int
|
||||||
if (len(ms.items) > 0) {
|
if len(ms.items) > 0 {
|
||||||
//fixme itemfield object, scroller, inputhandler, current selected item
|
//fixme itemfield object, scroller, inputhandler, current selected item
|
||||||
menuItems := make([]string, 0)
|
menuItems := make([]string, 0)
|
||||||
for i := ms.offset; i < len(ms.items); i++ {
|
for i := ms.offset; i < len(ms.items); i++ {
|
||||||
if string(ms.items[i].(string)) != "" {
|
if string(ms.items[i].(string)) != "" {
|
||||||
menuItems = append(menuItems, ms.items[i].(string))
|
menuItems = append(menuItems, ms.items[i].(string))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ilw, ilh = menuLayer.PrintInside(itemField, strings.Join(menuItems, "\n"), blt.TK_ALIGN_LEFT)
|
ilw, ilh = menuLayer.PrintInside(itemField, strings.Join(menuItems, "\n"), blt.TK_ALIGN_LEFT)
|
||||||
}
|
}
|
||||||
if ilh < len(ms.items) {
|
if ilh < len(ms.items) {
|
||||||
ms.drawScrollBar(menuLayer, itemField)
|
ms.drawScrollBar(menuLayer, itemField)
|
||||||
}
|
}
|
||||||
if ilw > itemField.W-4 {
|
if ilw > itemField.W-4 {
|
||||||
fmt.Printf("Excess width of item names found! Need h-scroll of certain names")
|
fmt.Printf("Excess width of item names found! Need h-scroll of certain names")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuScreen) drawScrollBar(menuLayer *mainwindow.Layer, itemField types.Rect) {
|
func (ms *MenuScreen) drawScrollBar(menuLayer *mainwindow.Layer, itemField types.Rect) {
|
||||||
scrollbarBg := types.NewRect(itemField.X+itemField.W-2, itemField.Y + 1, 1, itemField.H - 4)
|
scrollbarBg := types.NewRect(itemField.X+itemField.W-2, itemField.Y+1, 1, itemField.H-4)
|
||||||
menuLayer.WithColor("#77000000").NewWindow(scrollbarBg).Splash()
|
menuLayer.WithColor("#77000000").NewWindow(scrollbarBg).Splash()
|
||||||
//tick
|
//tick
|
||||||
menuLayer.WithColor(ms.fgColor).Put(
|
menuLayer.WithColor(ms.fgColor).Put(
|
||||||
scrollbarBg.X,
|
scrollbarBg.X,
|
||||||
scrollbarBg.Y + int(float64(ms.offset) / float64(len(ms.items)) * float64(scrollbarBg.H)),
|
scrollbarBg.Y+int(float64(ms.offset)/float64(len(ms.items))*float64(scrollbarBg.H)),
|
||||||
"⏹",
|
"⏹",
|
||||||
)
|
)
|
||||||
menuLayer.WithColor(ms.fgColor).Put(itemField.X+itemField.W-2, itemField.Y+scrollbarBg.H + 1, "↓")
|
menuLayer.WithColor(ms.fgColor).Put(itemField.X+itemField.W-2, itemField.Y+scrollbarBg.H+1, "↓")
|
||||||
menuLayer.WithColor(ms.fgColor).Put(itemField.X+itemField.W-2, itemField.Y, "↑")
|
menuLayer.WithColor(ms.fgColor).Put(itemField.X+itemField.W-2, itemField.Y, "↑")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ func (ts *TitleScreen) UseEcs() bool { return false }
|
|||||||
func (ts *TitleScreen) Enter() {
|
func (ts *TitleScreen) Enter() {
|
||||||
blt.Clear()
|
blt.Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fixme key names to action constants!
|
||||||
func (ts *TitleScreen) HandleInput(input string) {
|
func (ts *TitleScreen) HandleInput(input string) {
|
||||||
switch input {
|
switch input {
|
||||||
case "n":
|
case "n":
|
||||||
@ -55,5 +57,5 @@ Roguebasin Libtcod Tutorial (c) 2010-2011, Jotaf Henriques
|
|||||||
Brogue 1.3 (c) 2010 Brian Walker
|
Brogue 1.3 (c) 2010 Brian Walker
|
||||||
Madness (c) 2010 hmp <humpolec@gmail.com>
|
Madness (c) 2010 hmp <humpolec@gmail.com>
|
||||||
BearLibTerminal (c) Cfyz 2009-2019 <http://foo.wyrd.name/en:bearlibterminal>
|
BearLibTerminal (c) Cfyz 2009-2019 <http://foo.wyrd.name/en:bearlibterminal>
|
||||||
Gogue (c) jcerise
|
Gogue (c) 2019 jcerise
|
||||||
`
|
`
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,16 +13,14 @@ type Screen interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ScreenManager struct {
|
type ScreenManager struct {
|
||||||
ctx context.Context
|
|
||||||
Screens map[string]Screen
|
Screens map[string]Screen
|
||||||
CurrentScreen Screen
|
CurrentScreen Screen
|
||||||
PreviousScreen Screen
|
PreviousScreen Screen
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScreenManager is a convenience/constructor method to properly initialize a new ScreenManager
|
// NewScreenManager is a convenience/constructor method to properly initialize a new ScreenManager
|
||||||
func NewScreenManager(ctx context.Context) *ScreenManager {
|
func NewScreenManager() *ScreenManager {
|
||||||
manager := ScreenManager{
|
manager := ScreenManager{
|
||||||
ctx:ctx,
|
|
||||||
Screens: make(map[string]Screen),
|
Screens: make(map[string]Screen),
|
||||||
CurrentScreen: nil,
|
CurrentScreen: nil,
|
||||||
}
|
}
|
||||||
@ -36,7 +33,7 @@ func (sm *ScreenManager) AddScreen(screenName string, screen Screen) {
|
|||||||
// A screen with the given name does not yet exist on the ScreenManager, go ahead and add it
|
// A screen with the given name does not yet exist on the ScreenManager, go ahead and add it
|
||||||
sm.Screens[screenName] = screen
|
sm.Screens[screenName] = screen
|
||||||
} else {
|
} else {
|
||||||
appctx.Logger(sm.ctx).Warn().Msgf("A screen with name %v was already added to the ScreenManager %v!", screenName, sm)
|
appctx.Logger().Warn().Msgf("A screen with name %v was already added to the ScreenManager %v!", screenName, sm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +46,7 @@ func (sm *ScreenManager) RemoveScreen(screenName string, screen Screen) {
|
|||||||
delete(sm.Screens, screenName)
|
delete(sm.Screens, screenName)
|
||||||
} else {
|
} else {
|
||||||
// A screen with the given name does not exist
|
// A screen with the given name does not exist
|
||||||
appctx.Logger(sm.ctx).Warn().Msgf("A screen with name %v was not found on ScreenManager %v!", screenName, sm)
|
appctx.Logger().Warn().Msgf("A screen with name %v was not found on ScreenManager %v!", screenName, sm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +81,6 @@ func (sm *ScreenManager) SetScreenByName(screenName string) {
|
|||||||
sm.CurrentScreen.Enter()
|
sm.CurrentScreen.Enter()
|
||||||
} else {
|
} else {
|
||||||
// A screen with the given name does not exist
|
// A screen with the given name does not exist
|
||||||
appctx.Logger(sm.ctx).Warn().Msgf("A screen with name %v was not found on ScreenManager %v!", screenName, sm)
|
appctx.Logger().Warn().Msgf("A screen with name %v was not found on ScreenManager %v!", screenName, sm)
|
||||||
}
|
}
|
||||||
}
|
}
|
1
go.mod
1
go.mod
@ -6,5 +6,6 @@ require (
|
|||||||
github.com/gammazero/deque v0.0.0-20190521012701-46e4ffb7a622
|
github.com/gammazero/deque v0.0.0-20190521012701-46e4ffb7a622
|
||||||
github.com/rs/zerolog v1.15.0
|
github.com/rs/zerolog v1.15.0
|
||||||
github.com/shopspring/decimal v1.3.1
|
github.com/shopspring/decimal v1.3.1
|
||||||
|
github.com/stretchr/testify v1.8.0
|
||||||
lab.zaar.be/thefish/bearlibterminal v0.0.0-20191018101635-dd37bbc90d77
|
lab.zaar.be/thefish/bearlibterminal v0.0.0-20191018101635-dd37bbc90d77
|
||||||
)
|
)
|
||||||
|
16
go.sum
16
go.sum
@ -1,19 +1,33 @@
|
|||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/gammazero/deque v0.0.0-20190521012701-46e4ffb7a622 h1:lxbhOGZ9pU3Kf8P6lFluUcE82yVZn2EqEf4+mWRNPV0=
|
github.com/gammazero/deque v0.0.0-20190521012701-46e4ffb7a622 h1:lxbhOGZ9pU3Kf8P6lFluUcE82yVZn2EqEf4+mWRNPV0=
|
||||||
github.com/gammazero/deque v0.0.0-20190521012701-46e4ffb7a622/go.mod h1:D90+MBHVc9Sk1lJAbEVgws0eYEurY4mv2TDso3Nxh3w=
|
github.com/gammazero/deque v0.0.0-20190521012701-46e4ffb7a622/go.mod h1:D90+MBHVc9Sk1lJAbEVgws0eYEurY4mv2TDso3Nxh3w=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||||
github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY=
|
github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY=
|
||||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc h1:N3zlSgxkefUH/ecsl37RWTkESTB026kmXzNly8TuZCI=
|
|
||||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
lab.zaar.be/thefish/bearlibterminal v0.0.0-20191018101635-dd37bbc90d77 h1:ElfFSOSxp1PViWH7+iKZ8sZvEhaKN9o3vt13+hX2yaE=
|
lab.zaar.be/thefish/bearlibterminal v0.0.0-20191018101635-dd37bbc90d77 h1:ElfFSOSxp1PViWH7+iKZ8sZvEhaKN9o3vt13+hX2yaE=
|
||||||
lab.zaar.be/thefish/bearlibterminal v0.0.0-20191018101635-dd37bbc90d77/go.mod h1:tV7Vxx6vf9dPgj9B+RPeSrmtRl8nTSH07HIyBSSnEc4=
|
lab.zaar.be/thefish/bearlibterminal v0.0.0-20191018101635-dd37bbc90d77/go.mod h1:tV7Vxx6vf9dPgj9B+RPeSrmtRl8nTSH07HIyBSSnEc4=
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
1 Почему Go?
|
||||||
|
---
|
||||||
|
|
||||||
|
потому что круто. (тут бла-бла про управление памятью, многопоточность, сборку и либы)
|
||||||
|
|
||||||
|
2 Почему Libbearterminal?
|
||||||
|
---
|
||||||
|
|
||||||
|
Дьявол предложил расчесать манту.
|
||||||
|
|
||||||
|
3 Почему нет звука?
|
||||||
|
---
|
||||||
|
|
||||||
|
Бля, да лень возиться. И ни к чему это тут.
|
@ -155,6 +155,9 @@ func (tr *TerrainRender) Render() {
|
|||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
TODO: троттлинг
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### Каналы состояний и их Listеner-ы
|
#### Каналы состояний и их Listеner-ы
|
||||||
|
|
||||||
@ -167,7 +170,7 @@ func (tr *TerrainRender) Render() {
|
|||||||
|
|
||||||
- reflect в main loop. Лишь **только** выкинув рефлкесию и больше ничего не делая - я снизил потребление CPU приложением
|
- reflect в main loop. Лишь **только** выкинув рефлкесию и больше ничего не делая - я снизил потребление CPU приложением
|
||||||
**вдвое**. Это удобная штука, не спорю, но пользоваться ей надо при загрузке ресурсов, при сохранении/загрузке состояния
|
**вдвое**. Это удобная штука, не спорю, но пользоваться ей надо при загрузке ресурсов, при сохранении/загрузке состояния
|
||||||
приложения - т.е. при разовых операциях. Как оказалось, она _очень_ дорогая по CPU. Кто пользоуется ей в main loop, ORM
|
приложения - т.е. при разовых операциях. Как оказалось, она _очень_ дорогая по CPU. Кто пользуется ей в main loop, ORM
|
||||||
и прочих нагруженных местах - да будет предан анафеме.
|
и прочих нагруженных местах - да будет предан анафеме.
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ RLG и Golang - некоторые полезные советы
|
|||||||
1. [Установка и некоторые особенности работы](linux_go_blt_install_quickstart.md) связки BLT + Go на Linux
|
1. [Установка и некоторые особенности работы](linux_go_blt_install_quickstart.md) связки BLT + Go на Linux
|
||||||
2. Что [стоит и НЕ стоит](go_game_dos_and_donts.md) делать с возможностями Go - +chans, +tickers, +throttling, -closures
|
2. Что [стоит и НЕ стоит](go_game_dos_and_donts.md) делать с возможностями Go - +chans, +tickers, +throttling, -closures
|
||||||
3. [Система типов](./static_types_vs_ecs.md) - нативная или ECS? На самом деле и то, и то
|
3. [Система типов](./static_types_vs_ecs.md) - нативная или ECS? На самом деле и то, и то
|
||||||
|
4. Немножко конкретики: [предметы и обращение с ними](./item_objecttypes_and_blueprints.md). Как правильно готовить
|
||||||
|
предметы - чтобы потом не было мучительно больно.
|
||||||
|
|
||||||
Дополнения
|
Дополнения
|
||||||
---
|
---
|
||||||
|
16
story/item_objecttypes_and_blueprints.md
Normal file
16
story/item_objecttypes_and_blueprints.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Blueprints, паттерн Object Type и сериализация
|
||||||
|
==
|
||||||
|
|
||||||
|
Посмотрите внимательно вот это видео, [чувак дело говорит](https://www.youtube.com/watch?v=JxI3Eu5DPwE).
|
||||||
|
|
||||||
|
|
||||||
|
Итого:
|
||||||
|
|
||||||
|
- Всё что может делать предмет - в типы - или компоненты, если решились на ECS.
|
||||||
|
- Суперкласс/архетип для предмета
|
||||||
|
- Всё данные предмета - в человекочитаемый формат, json например
|
||||||
|
- Код для сериализации данных в экземпляр а памяти и обратно - **тщательно тестируем**! (TODO: примеры смешных багов)
|
||||||
|
- Названия типов - тоже в json, ни грамма данных врагу (т.е. коду). Позволит быстро менять/модифицировать игру чуть ли
|
||||||
|
не текстовым редактором.
|
||||||
|
|
||||||
|
И кстати. Чертежи не только на предметы работают, но об этом с следующей главе.
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
Почему это важно
|
Почему это важно
|
||||||
---
|
---
|
||||||
Про сборку под разные ОС я даже уюеждать не буду - аудитория рогаликов мало того что крохотная, так еще и сильно
|
Про сборку под разные ОС я даже убеждать не буду - аудитория рогаликов мало того что крохотная, так еще и сильно
|
||||||
сегментирована по осям. Go почти бесплатно дает вам возможность сборки под все мажорные оси, пользуйтесь этим - и
|
сегментирована по осям. Go почти бесплатно дает вам возможность сборки под все мажорные оси, пользуйтесь этим - и
|
||||||
потенциально в разы больше народа ознакомится с вашим творением.
|
потенциально в разы больше народа ознакомится с вашим творением.
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
Система типов в Go
|
Система типов и Go
|
||||||
|
---
|
||||||
|
|
||||||
Плюсы использования нативной системы типов
|
Плюсы использования нативной системы типов
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ type MainWindow struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Init(ctx context.Context) *MainWindow {
|
func Init(ctx context.Context) *MainWindow {
|
||||||
appctx.Logger(ctx).Info().Msgf("Opening main window...")
|
appctx.Logger().Info().Msgf("Opening main window...")
|
||||||
mw := MainWindow{ctx: ctx, layers: make(map[string]types.Renderable, 0)}
|
mw := MainWindow{ctx: ctx, layers: make(map[string]types.Renderable, 0)}
|
||||||
mw.Open()
|
mw.Open()
|
||||||
return &mw
|
return &mw
|
||||||
@ -33,7 +33,7 @@ func (mw *MainWindow) GetLayer(name string) *Layer {
|
|||||||
if layer, ok := mw.layers[name]; ok {
|
if layer, ok := mw.layers[name]; ok {
|
||||||
return layer.(*Layer)
|
return layer.(*Layer)
|
||||||
}
|
}
|
||||||
appctx.Logger(mw.ctx).Fatal().Msgf("No layer with such name %s", name)
|
appctx.Logger().Fatal().Msgf("No layer with such name %s", name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ func (mw *MainWindow) Open() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mw *MainWindow) Close() {
|
func (mw *MainWindow) Close() {
|
||||||
appctx.Logger(mw.ctx).Info().Msg("Closing main window...")
|
appctx.Logger().Info().Msg("Closing main window...")
|
||||||
blt.Close()
|
blt.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ type ViewPort struct {
|
|||||||
|
|
||||||
func NewViewPort(x, y, w, h int) *ViewPort {
|
func NewViewPort(x, y, w, h int) *ViewPort {
|
||||||
vp := ViewPort{
|
vp := ViewPort{
|
||||||
Rect: types.Rect{x, y, w, h},
|
Rect: types.Rect{X: x, Y: y, W: w, H: h},
|
||||||
}
|
}
|
||||||
return &vp
|
return &vp
|
||||||
}
|
}
|
||||||
@ -47,8 +47,8 @@ func (vp *ViewPort) ToVPCoords(c types.Coords) (newCoords types.Coords, err erro
|
|||||||
//coords on map to coords on vp
|
//coords on map to coords on vp
|
||||||
x, y := c.X-vp.CameraCoords.X, c.Y-vp.CameraCoords.Y
|
x, y := c.X-vp.CameraCoords.X, c.Y-vp.CameraCoords.Y
|
||||||
if x < 0 || y < 0 || x > vp.W || y > vp.H {
|
if x < 0 || y < 0 || x > vp.W || y > vp.H {
|
||||||
return types.Coords{-1, -1}, fmt.Errorf("Not in viewport: {%d, %d}", x, y)
|
return types.Coords{X: -1, Y: -1}, fmt.Errorf("Not in viewport: {%d, %d}", x, y)
|
||||||
}
|
}
|
||||||
return types.Coords{x, y}, nil
|
return types.Coords{X: x, Y: y}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,15 +12,17 @@ const (
|
|||||||
loggerKey = "logger"
|
loggerKey = "logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClientCtx struct {
|
type clientCtx struct {
|
||||||
context.Context
|
context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientContext(config *util.Config, logger *zerolog.Logger) ClientCtx {
|
var ClientState clientCtx
|
||||||
|
|
||||||
|
func NewClientContext(config *util.Config, logger *zerolog.Logger) {
|
||||||
ctx := context.Context(context.TODO())
|
ctx := context.Context(context.TODO())
|
||||||
ctx = context.WithValue(ctx, configKey, config)
|
ctx = context.WithValue(ctx, configKey, config)
|
||||||
ctx = context.WithValue(ctx, loggerKey, logger)
|
ctx = context.WithValue(ctx, loggerKey, logger)
|
||||||
return ClientCtx{ ctx}
|
ClientState = clientCtx{ctx}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Config(c context.Context) *util.Config {
|
func Config(c context.Context) *util.Config {
|
||||||
@ -31,7 +33,11 @@ func Config(c context.Context) *util.Config {
|
|||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func Logger(c context.Context) *zerolog.Logger {
|
func Logger() *zerolog.Logger {
|
||||||
|
return getLogger(ClientState.Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLogger(c context.Context) *zerolog.Logger {
|
||||||
logger, ok := c.Value(loggerKey).(*zerolog.Logger)
|
logger, ok := c.Value(loggerKey).(*zerolog.Logger)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Errorf("no access to logger from context"))
|
panic(fmt.Errorf("no access to logger from context"))
|
||||||
|
@ -6,6 +6,7 @@ import "lab.zaar.be/thefish/alchemyst-go/engine/types"
|
|||||||
|
|
||||||
var nodeId = 0
|
var nodeId = 0
|
||||||
var nodeList = make(map[types.Coords]Node, 0)
|
var nodeList = make(map[types.Coords]Node, 0)
|
||||||
|
|
||||||
// Node defines a struct having as components the node X and Y coordinate position.
|
// Node defines a struct having as components the node X and Y coordinate position.
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Id int
|
Id int
|
||||||
@ -129,17 +130,27 @@ func (d *Delaunay) Init(width, height int) *Delaunay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var supertriangle1, supertriangle2 Triangle
|
var supertriangle1, supertriangle2 Triangle
|
||||||
|
|
||||||
// clear method clears the delaunay triangles slice.
|
// clear method clears the delaunay triangles slice.
|
||||||
func (d *Delaunay) clear() {
|
func (d *Delaunay) clear() {
|
||||||
p0 := newNode(types.Coords{0,0})
|
p0 := newNode(types.Coords{X: 0, Y: 0})
|
||||||
p1 := newNode(types.Coords{d.width, 0})
|
p1 := newNode(types.Coords{X: d.width, Y: 0})
|
||||||
p2 := newNode(types.Coords{d.width, d.height})
|
p2 := func() Node {
|
||||||
p3 := newNode(types.Coords{0, d.height})
|
var coords types.Coords = types.Coords{X: d.width, Y: d.height}
|
||||||
|
if n, ok := nodeList[coords]; ok {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
neue := Node{Id: nodeId, Coords: coords}
|
||||||
|
nodeList[coords] = neue
|
||||||
|
nodeId++
|
||||||
|
return neue
|
||||||
|
}()
|
||||||
|
p3 := newNode(types.Coords{X: 0, Y: d.height})
|
||||||
|
|
||||||
// Create the supertriangle, an artificial triangle which encompasses all the points.
|
// Create the supertriangle, an artificial triangle which encompasses all the points.
|
||||||
// At the end of the triangulation process any triangles which share Edges with the supertriangle are deleted from the triangle list.
|
// At the end of the triangulation process any triangles which share Edges with the supertriangle are deleted from the triangle list.
|
||||||
supertriangle1 = t.newTriangle(p0,p1,p2)
|
supertriangle1 = t.newTriangle(p0, p1, p2)
|
||||||
supertriangle2 = t.newTriangle(p0,p2,p3)
|
supertriangle2 = t.newTriangle(p0, p2, p3)
|
||||||
d.triangles = []Triangle{supertriangle1, supertriangle2}
|
d.triangles = []Triangle{supertriangle1, supertriangle2}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +210,7 @@ func (d *Delaunay) Insert(points []types.Coords) *Delaunay {
|
|||||||
}
|
}
|
||||||
for i = 0; i < len(polygon); i++ {
|
for i = 0; i < len(polygon); i++ {
|
||||||
edge := polygon[i]
|
edge := polygon[i]
|
||||||
temps = append(temps, t.newTriangle(edge.Nodes[0], edge.Nodes[1], newNode(types.Coords{x, y})))
|
temps = append(temps, t.newTriangle(edge.Nodes[0], edge.Nodes[1], newNode(types.Coords{X: x, Y: y})))
|
||||||
}
|
}
|
||||||
d.triangles = temps
|
d.triangles = temps
|
||||||
}
|
}
|
||||||
@ -245,12 +256,9 @@ func (d *Delaunay) GetTriangles() []Triangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Delaunay) GetEdges() []Edge {
|
func (d *Delaunay) GetEdges() []Edge {
|
||||||
edges := make([]Edge, 0)
|
edges := make([]Edge, 0)
|
||||||
for _, trs := range d.triangles {
|
for _, trs := range d.triangles {
|
||||||
for _, e := range trs.Edges {
|
edges = append(edges, trs.Edges...)
|
||||||
edges = append(edges, e)
|
}
|
||||||
}
|
return edges
|
||||||
|
|
||||||
}
|
|
||||||
return edges
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ func GetTriangles(coords []types.Coords, w, h int) []types.Edge {
|
|||||||
edges := d.Init(100, 100).Insert(coords).GetEdges()
|
edges := d.Init(100, 100).Insert(coords).GetEdges()
|
||||||
output := make([]types.Edge, 0)
|
output := make([]types.Edge, 0)
|
||||||
for _, e := range edges{
|
for _, e := range edges{
|
||||||
output = append(output, types.Edge{e.Nodes[0].Coords, e.Nodes[1].Coords})
|
output = append(output, types.Edge{From: e.Nodes[0].Coords, To: e.Nodes[1].Coords})
|
||||||
}
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
@ -46,16 +46,16 @@ func GetMst(coords []types.Coords, w, h, negativeWeight int) []types.Edge {
|
|||||||
graph = append(
|
graph = append(
|
||||||
graph,
|
graph,
|
||||||
kruskals.SimpleWeightedEdge{
|
kruskals.SimpleWeightedEdge{
|
||||||
nodeMap[e.Nodes[0].Id],
|
F: nodeMap[e.Nodes[0].Id],
|
||||||
nodeMap[e.Nodes[1].Id],
|
T: nodeMap[e.Nodes[1].Id],
|
||||||
negativeWeight - int(e.Nodes[0].Coords.DistanceTo(e.Nodes[1].Coords))},
|
W: negativeWeight - int(e.Nodes[0].Coords.DistanceTo(e.Nodes[1].Coords))},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
result := kruskals.MinimumSpanningTree(graph)
|
result := kruskals.MinimumSpanningTree(graph)
|
||||||
output := make([]types.Edge, 0)
|
output := make([]types.Edge, 0)
|
||||||
for _, we := range result{
|
for _, we := range result{
|
||||||
output = append(output, types.Edge{nodeList[we.From()].Coords, nodeList[we.To()].Coords})
|
output = append(output, types.Edge{From: nodeList[we.From()].Coords, To: nodeList[we.To()].Coords})
|
||||||
}
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
78
util/wu/line.go
Normal file
78
util/wu/line.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package wu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ipart(x float64) float64 {
|
||||||
|
return math.Floor(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func round(x float64) float64 {
|
||||||
|
return ipart(x + .5)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fpart(x float64) float64 {
|
||||||
|
return x - ipart(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rfpart(x float64) float64 {
|
||||||
|
return 1 - fpart(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Layer types.Putable) WuLine(x1, y1, x2, y2 float64, w int) {
|
||||||
|
dx := x2 - x1
|
||||||
|
dy := y2 - y1
|
||||||
|
ax := dx
|
||||||
|
if ax < 0 {
|
||||||
|
ax = -ax
|
||||||
|
}
|
||||||
|
ay := dy
|
||||||
|
if ay < 0 {
|
||||||
|
ay = -ay
|
||||||
|
}
|
||||||
|
|
||||||
|
var plot func(int, int, float64)
|
||||||
|
|
||||||
|
if ax < ay {
|
||||||
|
x1, y1 = y1, x1
|
||||||
|
x2, y2 = y2, x2
|
||||||
|
dx, dy = dy, dx
|
||||||
|
plot = func(x, y int, c float64) {
|
||||||
|
Layer.Put(y, x, uint8(255 * c))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
plot = func(x, y int, c float64) {
|
||||||
|
Layer.Put(x, y, uint8(255 * c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if x2 < x1 {
|
||||||
|
x1, x2 = x2, x1
|
||||||
|
y1, y2 = y2, y1
|
||||||
|
}
|
||||||
|
gradient := dy / dx
|
||||||
|
|
||||||
|
xend := round(x1)
|
||||||
|
yend := y1 + gradient*(xend-x1)
|
||||||
|
xgap := rfpart(x1 + .5)
|
||||||
|
xpxl1 := int(xend)
|
||||||
|
ypxl1 := int(ipart(yend))
|
||||||
|
plot(xpxl1, ypxl1, rfpart(yend)*xgap)
|
||||||
|
plot(xpxl1, ypxl1+1, fpart(yend)*xgap)
|
||||||
|
intery := yend + gradient
|
||||||
|
|
||||||
|
xend = round(x2)
|
||||||
|
yend = y2 + gradient*(xend-x2)
|
||||||
|
xgap = fpart(x2 + 0.5)
|
||||||
|
xpxl2 := int(xend)
|
||||||
|
ypxl2 := int(ipart(yend))
|
||||||
|
plot(xpxl2, ypxl2, rfpart(yend)*xgap)
|
||||||
|
plot(xpxl2, ypxl2+1, fpart(yend)*xgap)
|
||||||
|
|
||||||
|
for x := xpxl1 + 1; x <= xpxl2-1; x++ {
|
||||||
|
plot(x, int(ipart(intery)), rfpart(intery))
|
||||||
|
plot(x, int(ipart(intery))+1, fpart(intery))
|
||||||
|
intery = intery + gradient
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user