ui starting, menu screen, ingame help

This commit is contained in:
thefish 2019-11-08 03:36:26 +03:00
parent 4532320ce3
commit cb7718860a
11 changed files with 271 additions and 40 deletions

View File

@ -59,7 +59,6 @@ func main() {
// set up context // set up context
mainCtx := util.NewClientContext(config, &logger) mainCtx := util.NewClientContext(config, &logger)
//set up main window //set up main window
mw := mainwindow.Init(mainCtx) mw := mainwindow.Init(mainCtx)
defer mw.Close() defer mw.Close()
@ -69,7 +68,6 @@ func main() {
//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 //fixme set up (load / generate) level
level, rooms := mapgens.DefaultGen(gamemap.NewLevel(mainCtx, "test", 1)) level, rooms := mapgens.DefaultGen(gamemap.NewLevel(mainCtx, "test", 1))
State.Level = level State.Level = level
@ -78,7 +76,6 @@ func main() {
vp := mainwindow.NewViewPort(30, 0, (mw.W - 30), (mw.H - 0), mw.GetLayer("base")) vp := mainwindow.NewViewPort(30, 0, (mw.W - 30), (mw.H - 0), mw.GetLayer("base"))
go vp.Listen(State) go vp.Listen(State)
//set up controller //set up controller
controller := ecs.NewController() controller := ecs.NewController()
@ -90,16 +87,39 @@ func main() {
moveable := movement.Moveable{ moveable := movement.Moveable{
Controller: controller, Controller: controller,
Level: level, Level: level,
} }
//Set up Screen Manager //Set up Screen Manager
screenMgr := types.NewScreenManager(mainCtx) screenMgr := types.NewScreenManager(mainCtx)
screenMgr.AddScreen("title", &screens.TitleScreen{}) screenMgr.AddScreen("title", screens.NewTitleScreen(mw, screenMgr))
screenMgr.AddScreen("game", screens.NewGameScreen(mw, &State, vp, controller)) screenMgr.AddScreen("game", screens.NewGameScreen(mw, &State, vp, controller, screenMgr))
screenMgr.AddScreen("help", screens.NewMenuScreen(
mw,
screenMgr,
"Help",
"Keybindings:",
//"[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),
true, ).
SetBgColor("#ef1d494f").
SetFgColor("white").
SetItems([]interface{}{
"hjklyubn 12346789 or arrow keys - move",
"s or . - pass turn",
"g or , - pick up item",
"i - inventory",
"? - this screen",
"Ctrl+q - exit",
"f or F - fire or throw weapon",
"z or Z - cast a spell",
"p - pray",
"Ctrl+p - message log",
}),
)
screenMgr.SetScreenByName("game") screenMgr.SetScreenByName("title")
//fixme //fixme
//player := &mob.Player{ //player := &mob.Player{
@ -119,7 +139,6 @@ func main() {
//vp.PlayerCoords = player.Coords //vp.PlayerCoords = player.Coords
//vp.Render(&State) //vp.Render(&State)
//fixme set up (load / generate) player //fixme set up (load / generate) player
player := controller.CreateEntity([]ecs.Component{}) player := controller.CreateEntity([]ecs.Component{})
@ -153,9 +172,10 @@ func main() {
mainCtx.Logger().Warn().Msg("quitting NOW") mainCtx.Logger().Warn().Msg("quitting NOW")
exit = true exit = true
break break
// не оставляйте default в бесконесчном select {} - сожрет всё CPU // не оставляйте default в бесконечном select {} - сожрет всё CPU
default: default:
screenMgr.CurrentScreen.Render() screenMgr.CurrentScreen.Render()
blt.Layer(0) //return to base layer
blt.Refresh() blt.Refresh()
} }
@ -166,7 +186,8 @@ func main() {
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("menu", 2, "white") mainwindow.AddLayer("menubg", 2, "white")
mainwindow.AddLayer("menu", 3, "white")
} }
func decodeInput(ctx util.ClientCtx, baseLayer *mainwindow.Layer) { func decodeInput(ctx util.ClientCtx, baseLayer *mainwindow.Layer) {
@ -208,8 +229,8 @@ func decodeInput(ctx util.ClientCtx, baseLayer *mainwindow.Layer) {
blt.Set("window: size=100x47; font: ./resources/fonts-ttf/UbuntuMono-R.ttf, size=11;") blt.Set("window: size=100x47; font: ./resources/fonts-ttf/UbuntuMono-R.ttf, size=11;")
}) })
case "Ctrl+q": case "Ctrl+q":
fallthrough //fallthrough
case "Escape": //case "Escape":
ctx.Logger().Info().Msg("exiting on quit command...") ctx.Logger().Info().Msg("exiting on quit command...")
State.Exit <- struct{}{} State.Exit <- struct{}{}
ctx.Logger().Info().Msg("...done") ctx.Logger().Info().Msg("...done")

View File

@ -24,6 +24,9 @@ func DefaultGen(l *gamemap.Level) (*gamemap.Level, []*gamemap.Room) {
rooms := make([]*gamemap.Room, 0) rooms := make([]*gamemap.Room, 0)
//one wall around whole level guaranteed
levelBoundary := types.NewRect(l.X + 1, l.Y + 1, l.W - 2, l.H - 2)
for i := 0; i < maxrooms; i++ { for i := 0; i < maxrooms; i++ {
newRoom := &gamemap.Room{ newRoom := &gamemap.Room{
Rect: types.NewRect( Rect: types.NewRect(
@ -36,7 +39,7 @@ func DefaultGen(l *gamemap.Level) (*gamemap.Level, []*gamemap.Room) {
failed := false failed := false
if !l.InBounds(types.Coords{newRoom.X, newRoom.Y}) { if !levelBoundary.InBounds(types.Coords{newRoom.X, newRoom.Y}) {
failed = true failed = true
} }

View File

@ -14,18 +14,24 @@ type GameScreen struct {
state *gamestate.GameState state *gamestate.GameState
vp *mainwindow.ViewPort vp *mainwindow.ViewPort
controller *ecs.Controller controller *ecs.Controller
scm *types.ScreenManager
} }
func NewGameScreen(mw *mainwindow.MainWindow, state *gamestate.GameState, viewPort *mainwindow.ViewPort, controller *ecs.Controller) *GameScreen { func NewGameScreen(mw *mainwindow.MainWindow, state *gamestate.GameState, viewPort *mainwindow.ViewPort, controller *ecs.Controller, scm *types.ScreenManager) *GameScreen {
return &GameScreen{mw: mw, state: state, vp: viewPort, controller: controller} ts := &GameScreen{mw: mw, state: state, vp: viewPort, controller: controller, scm: scm}
renderMobs := systems.MobRenderSystem{EntityController: ts.controller}
ts.controller.AddSystem(renderMobs, 1)
return ts
} }
func (ts *GameScreen) UseEcs() bool { return true } func (ts *GameScreen) UseEcs() bool { return true }
func (ts *GameScreen) Enter() { func (ts *GameScreen) Enter() {
renderMobs := systems.MobRenderSystem{EntityController: ts.controller} ts.mw.GetLayer("overlay").ClearArea(0, ts.mw.H - 3, 30, 3)
ts.controller.AddSystem(renderMobs, 1) ts.mw.GetLayer("overlay").WithColor("#77777777").
Print(1, ts.mw.H - 2, "Press [color=white]?[/color] for help")
} }
func (ts *GameScreen) Exit() { func (ts *GameScreen) Exit() {
ts.mw.GetLayer("base").ClearArea(1, ts.mw.H -2, 30, 1)
//remove what we dont need //remove what we dont need
} }
@ -56,6 +62,9 @@ func (ts *GameScreen) HandleInput(input string) {
case "n", "3": case "n", "3":
ts.walk(ts.state, 1, 1) ts.walk(ts.state, 1, 1)
break break
case "Shift+/":
ts.scm.SetScreenByName("help")
break
default: default:
ts.mw.GetLayer("base").ClearArea(0, 3, 40, 1) ts.mw.GetLayer("base").ClearArea(0, 3, 40, 1)
ts.mw.GetLayer("base").Print(1, 3, "Key: "+input) ts.mw.GetLayer("base").Print(1, 3, "Key: "+input)

116
engine/screens/menu.go Normal file
View File

@ -0,0 +1,116 @@
package screens
import (
"lab.zaar.be/thefish/alchemyst-go/engine/types"
"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
blt "lab.zaar.be/thefish/bearlibterminal"
"strings"
)
const runeIndex = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
type MenuScreen struct {
*types.Rect
mw *mainwindow.MainWindow
scm *types.ScreenManager
renderParent bool
items []interface{}
title string
header string
footer string
redraw bool
bgColor string
fgColor string
}
func NewMenuScreen(mw *mainwindow.MainWindow, scm *types.ScreenManager, title, header, footer string, rect *types.Rect, renderParent bool) *MenuScreen {
return &MenuScreen{
title: title,
header: header,
footer: footer,
Rect: rect,
mw: mw,
scm: scm,
renderParent: renderParent,
}
}
func (ms *MenuScreen) SetBgColor(color string) *MenuScreen {
ms.bgColor = color
return ms
}
func (ms *MenuScreen) SetFgColor(color string) *MenuScreen {
ms.fgColor = color
return ms
}
//fixme!!
func (ms *MenuScreen) SetItems(items []interface{}) *MenuScreen {
ms.items = items
return ms
}
func (ms *MenuScreen) UseEcs() bool { return false }
func (ms *MenuScreen) Enter() {
ms.redraw = true
}
func (ms *MenuScreen) HandleInput(input string) {
//
//if input != "" {
// ms.redraw = true
//}
switch input {
case "Space":
ms.scm.SetScreen(ms.scm.PreviousScreen)
break
}
}
func (ms *MenuScreen) Exit() {
menuLayer := ms.mw.GetLayer("menu")
menuLayer.ClearRect(ms.Rect)
bgLayer := ms.mw.GetLayer("menubg")
bgLayer.ClearRect(ms.Rect)
}
func (ms *MenuScreen) Render() {
if ms.renderParent {
ms.scm.PreviousScreen.Render()
}
if (ms.redraw || ms.renderParent) {
ms.redraw = false
menuLayer := ms.mw.GetLayer("menu")
menuLayer.ClearRect(ms.Rect)
bgLayer := ms.mw.GetLayer("menubg")
bgLayer.ClearRect(ms.Rect)
bgLayer.WithColor(ms.bgColor).NewWindow(ms.Rect).Splash()
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"+"╞")
footerHeight := 0
if ms.footer != "" {
_, footerHeight = menuLayer.PrintInside(ms.Rect, ms.footer, 9)
footerHeight = footerHeight + 2
}
_, 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
if (len(ms.items) > 0) {
//fixme itemfield object, scroller, inputhandler, current selected item
menuItems := make([]string, 0)
for i, _ := range ms.items {
if string(ms.items[i].(string)) != "" {
menuItems = append(menuItems, ms.items[i].(string))
}
}
menuLayer.PrintInside(&itemField, strings.Join(menuItems, "\n"), blt.TK_ALIGN_LEFT)
}
}
}

11
engine/screens/sample.go Normal file
View File

@ -0,0 +1,11 @@
package screens
type SampleScreen struct {
}
func (ss *SampleScreen) UseEcs() bool {return false}
func (ss *SampleScreen) Enter() {}
func (ss *SampleScreen) HandleInput(input string) {}
func (ss *SampleScreen) Exit() {}
func (ss *SampleScreen) Render() {}

View File

@ -1,11 +1,66 @@
package screens package screens
type TitleScreen struct { import (
"lab.zaar.be/thefish/alchemyst-go/engine/types"
"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
blt "lab.zaar.be/thefish/bearlibterminal"
)
type TitleScreen struct {
mw *mainwindow.MainWindow
scm *types.ScreenManager
} }
func (ts *TitleScreen) UseEcs() bool {return false} func NewTitleScreen(mw *mainwindow.MainWindow, scm *types.ScreenManager) *TitleScreen {
func (ts *TitleScreen) Enter() {} return &TitleScreen{mw: mw, scm: scm}
func (ts *TitleScreen) HandleInput(input string) {} }
func (ts *TitleScreen) Exit() {}
func (ts *TitleScreen) Render() {} func (ts *TitleScreen) UseEcs() bool { return false }
func (ts *TitleScreen) Enter() {
blt.Clear()
}
func (ts *TitleScreen) HandleInput(input string) {
switch input {
case "n":
ts.scm.SetScreenByName("game")
}
}
func (ts *TitleScreen) Exit() {
blt.Clear()
}
func (ts *TitleScreen) Render() {
blt.PrintExt(0, 0, ts.mw.W, ts.mw.H, 15, logo)
}
var logo = `
.ddxo. .c c xlx
.kd. .0o:O, c0uO'
xc 0; x: ko ,,
;l Y; c, .Yct;
.. .. .......
:o: :k; .cxloOo x0. kO .olldk; do .;k lO. dO 'xllxk; ocokk:dl
.lKO, .kl 'dl c l0l..;dK lkx..;d: dOx .cOx ,0o c0 kk. .Y .Oo
.l0.k0. .0l lK. l0oxxxOK OK;xxx kKOklOkx ,kO;'do. ;xO: .Oo
:OoooxO .Ol ;Xc , cK' dK xX. , Ox YY xx ,O0. . .oKx. .0o
;k. .Ox Ok..'.,l ;Kk:;dk cKl lX: dKc,;oc kx kk OO dKl;lk: .0O
l; ,o .kK0KKK; :Ok; c; l: .oxc. x: Ol xl .dk: .o
Alchemyst (c) 2011-2014 thefish <thefish@zaar.be>
[color=green]N[/color]ew dungeon run
[color=green]L[/color]oad saved game
Read [color=green]h[/color]elp file
Highest [color=green]S[/color]cores
Roguebasin Libtcod Tutorial (c) 2010-2011, Jotaf Henriques
Brogue 1.3 (c) 2010 Brian Walker
Madness (c) 2010 hmp <humpolec@gmail.com>
BearLibTerminal (c) Cfyz 2009-2019 <http://foo.wyrd.name/en:bearlibterminal>
Gogue (c) jcerise
`

View File

@ -12,10 +12,16 @@ func NewRect(x, y, w, h int) *Rect {
return &Rect{x, y, w, h} return &Rect{x, y, w, h}
} }
func NewCenteredRect(source *Rect, w, h int) *Rect {
targetX := source.X + source.W / 2 - w / 2
targetY := source.Y + source.H / 2 - h / 2
return &Rect{targetX, targetY, w, h}
}
func (r *Rect) Blit(fillage RectFill, layer Putable) { func (r *Rect) Blit(fillage RectFill, layer Putable) {
if fillage.Body != "" { if fillage.Body != "" {
for i := r.X + 1; i < r.X+r.W; i++ { for i := r.X+1; i < r.X+r.W - 1; i++ {
for j := r.Y + 1; j < r.Y+r.H; j++ { for j := r.Y + 1; j < r.Y+r.H; j++ {
layer.Put(i, j, fillage.Body) layer.Put(i, j, fillage.Body)
//lii.Put(i, j, "X"); //lii.Put(i, j, "X");
@ -23,27 +29,27 @@ func (r *Rect) Blit(fillage RectFill, layer Putable) {
} }
} }
for i := r.X + 1; i < r.X+r.W; i++ { for i := r.X; i < r.X+r.W - 1; i++ {
layer.Put(i, r.Y, fillage.Top) layer.Put(i, r.Y, fillage.Top)
//lii.Put(i, Y-1, "Q"); //lii.Put(i, Y-1, "Q");
layer.Put(i, r.Y+r.H, fillage.Bottom) layer.Put(i, r.Y+r.H - 1, fillage.Bottom)
//lii.Put(i, Y+H, "H"); //lii.Put(i, Y+H, "H");
} }
for j := r.Y + 1; j < r.Y+r.H; j++ { for j := r.Y; j < r.Y+r.H; j++ {
layer.Put(r.X, j, fillage.Left) layer.Put(r.X, j, fillage.Left)
//lii.Put(X-1, j, "U"); //lii.Put(X-1, j, "U");
layer.Put(r.X+r.W, j, fillage.Right) layer.Put(r.X+r.W - 1, j, fillage.Right)
//lii.Put(X+W, j, "M"); //lii.Put(X+W, j, "M");
} }
layer.Put(r.X, r.Y, fillage.TopLeft) layer.Put(r.X, r.Y, fillage.TopLeft)
//lii.Put(X-1, Y-1, "T"); //lii.Put(X-1, Y-1, "T");
layer.Put(r.X, r.Y+r.H, fillage.BottomLeft) layer.Put(r.X, r.Y+r.H - 1, fillage.BottomLeft)
//lii.Put(X-1, Y+H, "q"); //lii.Put(X-1, Y+H, "q");
layer.Put(r.X+r.W, r.Y, fillage.TopRight) layer.Put(r.X+r.W - 1, r.Y, fillage.TopRight)
//lii.Put(X+W, Y-1, "L"); //lii.Put(X+W, Y-1, "L");
layer.Put(r.X+r.W, r.Y+r.H, fillage.BottomRight) layer.Put(r.X+r.W - 1, r.Y+r.H - 1, fillage.BottomRight)
} }
func (self *Rect) Intersects(other *Rect) bool { func (self *Rect) Intersects(other *Rect) bool {

View File

@ -6,12 +6,12 @@ import (
) )
type Layer struct { type Layer struct {
idx int Idx int
defaultColor uint32 defaultColor uint32
} }
func (layer *Layer) before() *Layer { func (layer *Layer) before() *Layer {
blt.Layer(layer.idx) blt.Layer(layer.Idx)
return layer return layer
} }
@ -61,6 +61,7 @@ func (Layer *Layer) PutToBase(x,y int, symbol interface{}, fg uint32, bg uint32)
rnes := []rune(symbol.(string)) rnes := []rune(symbol.(string))
prevColor := uint32(blt.State(blt.TK_COLOR)) prevColor := uint32(blt.State(blt.TK_COLOR))
prevBgColor := uint32(blt.State(blt.TK_BKCOLOR)) prevBgColor := uint32(blt.State(blt.TK_BKCOLOR))
blt.Layer(0)
blt.BkColor(bg) blt.BkColor(bg)
blt.Color(fg) blt.Color(fg)
if (len(rnes)) > 0 { if (len(rnes)) > 0 {
@ -87,7 +88,13 @@ func (layer Layer) Put(x, y int, symbol interface{}) {
} }
func (layer Layer) Print(x, y int, txt string) (w, h int) { func (layer Layer) Print(x, y int, txt string) (w, h int) {
return blt.Print(x, y, txt) w, h = blt.Print(x, y, txt)
//blt.Layer(0)
return w, h
}
func (layer Layer) PrintInside(rect *types.Rect, text string, alignment int) (width int, height int) {
return blt.PrintExt(rect.X + 2, rect.Y + 2, rect.W - 4, rect.H - 4, alignment, text)
} }
func (layer *Layer) Decorate(f func(args ...interface{})) func(args ...interface{}) { func (layer *Layer) Decorate(f func(args ...interface{})) func(args ...interface{}) {
@ -99,7 +106,10 @@ func (layer *Layer) Decorate(f func(args ...interface{})) func(args ...interface
} }
func (layer *Layer) ClearRect(r *types.Rect) { func (layer *Layer) ClearRect(r *types.Rect) {
prevLayer := int(blt.State(blt.TK_LAYER))
blt.Layer(layer.Idx)
blt.ClearArea(r.X, r.Y, r.W, r.H) blt.ClearArea(r.X, r.Y, r.W, r.H)
blt.Layer(prevLayer)
} }
func (layer *Layer) ClearArea(x,y,w,h int) { func (layer *Layer) ClearArea(x,y,w,h int) {

View File

@ -24,7 +24,7 @@ func Init(ctx util.ClientCtx) *MainWindow {
func (mw *MainWindow) AddLayer(name string, idx int, colorName string) *MainWindow { func (mw *MainWindow) AddLayer(name string, idx int, colorName string) *MainWindow {
c := blt.ColorFromName(colorName) c := blt.ColorFromName(colorName)
mw.layers[name] = &Layer{idx: idx, defaultColor: c} mw.layers[name] = &Layer{Idx: idx, defaultColor: c}
return mw return mw
} }

View File

@ -43,9 +43,9 @@ type UiWindow struct {
fillage types.RectFill fillage types.RectFill
} }
func (layer *Layer) NewWindow(x, y, w, h int) *UiWindow { func (layer *Layer) NewWindow(rect *types.Rect) *UiWindow {
return &UiWindow{ return &UiWindow{
Rect: types.NewRect(x, y, w, h), Rect: rect,
layer: layer, layer: layer,
} }
} }

View File

@ -105,8 +105,8 @@ func (vp *ViewPort) Render(state *gamestate.GameState) {
vp.Fov.ComputeFov(state.Level, playerCoords, vp.TorchRadius) vp.Fov.ComputeFov(state.Level, playerCoords, vp.TorchRadius)
} }
vp.layer.ClearArea(0, 7, 20, 1) //vp.layer.ClearArea(0, 7, 20, 1)
vp.layer.Print(0,7, fmt.Sprintf("pcds: %v", playerCoords)) //vp.layer.Print(0,7, fmt.Sprintf("pcds: %v", playerCoords))
if redraw { if redraw {