tins2020/gamecontrols.go

253 lines
7.4 KiB
Go

package tins2020
import (
"opslag.de/schobers/geom"
"opslag.de/schobers/zntg"
"opslag.de/schobers/zntg/play"
"opslag.de/schobers/zntg/ui"
)
const fpsOverlayName = "fps"
type GameControls struct {
ui.ContainerBase
game *Game
dialogs *Dialogs
menu ui.StackPanel
top ui.StackPanel
flowers ui.StackPanel
otherTools ui.StackPanel
pause *IconButton
run *IconButton
runFast *IconButton
shovel *IconButton
research *IconButton
}
func NewGameControls(game *Game, dialogs *Dialogs) *GameControls {
return &GameControls{game: game, dialogs: dialogs}
}
func (c *GameControls) askUserBeforeLoad(ctx ui.Context) {
c.dialogs.AskConfirmation(ctx,
"Do you want to load?",
"You will lose any progress you made during this session.",
func(ui.Context, interface{}) {
c.game.Load(ctx)
c.updateFlowerControls()
},
func(ui.Context, interface{}) {})
}
func (c *GameControls) askUserBeforeNew(ctx ui.Context) {
c.dialogs.AskConfirmation(ctx,
"Do you want to start a new game?",
"You will lose any progress you made during this session.",
func(ui.Context, interface{}) {
c.game.New(ctx)
c.updateFlowerControls()
},
func(ui.Context, interface{}) {})
}
func (c *GameControls) askUserBeforeSave(ctx ui.Context) {
c.dialogs.AskConfirmation(ctx,
"Do you want to save?",
"Saving will overwrite any previous save game.",
func(ui.Context, interface{}) { c.game.Save() },
func(ui.Context, interface{}) {})
}
func (c *GameControls) Init(ctx ui.Context) {
ctx.Overlays().AddOnTop(fpsOverlayName, &play.FPS{}, false)
c.game.SpeedChanged().AddHandler(c.speedChanged)
c.game.ToolChanged().AddHandler(c.toolChanged)
c.dialogs.DialogOpened().AddHandlerEmpty(func(ctx ui.Context) { c.game.Pause(ctx) })
c.dialogs.DialogClosed().AddHandlerEmpty(func(ctx ui.Context) {
c.updateFlowerControls()
c.game.Resume(ctx)
})
c.flowers.Background = zntg.MustHexColor("#356DAD")
for _, id := range c.game.Herbarium.Flowers() {
c.flowers.Children = append(c.flowers.Children, c.createBuyFlowerButton(id))
}
c.top.Orientation = ui.OrientationHorizontal
c.pause = NewIconButtonConfigure("control-pause", func(ctx ui.Context) {
c.game.Pause(ctx)
}, func(b *IconButton) {
b.DisabledColor = ctx.Style().Palette.Secondary
b.Tooltip = "Pause game"
})
c.run = NewIconButtonConfigure("control-run", func(ctx ui.Context) {
c.game.Run(ctx)
}, func(b *IconButton) {
b.DisabledColor = ctx.Style().Palette.Secondary
b.Tooltip = "Run game at normal speed"
})
c.runFast = NewIconButtonConfigure("control-run-fast", func(ctx ui.Context) {
c.game.RunFast(ctx)
}, func(b *IconButton) {
b.DisabledColor = ctx.Style().Palette.Secondary
b.Tooltip = "Run game at fast speed"
})
c.speedChanged(nil, c.game.Speed)
c.top.Children = []ui.Control{c.pause, c.run, c.runFast}
c.menu.Background = zntg.MustHexColor("#356DAD")
c.menu.Children = []ui.Control{
NewIconButtonConfigure("control-settings", c.dialogs.ShowSettings, func(b *IconButton) {
b.Disabled = true
b.DisabledColor = zntg.MustHexColor("#AFAFAF")
}),
NewIconButtonConfigure("control-save", c.askUserBeforeSave, func(b *IconButton) {
b.Tooltip = "Save game"
}),
NewIconButtonConfigure("control-load", c.askUserBeforeLoad, func(b *IconButton) {
b.Tooltip = "Load last saved game"
}),
NewIconButtonConfigure("control-new", c.askUserBeforeNew, func(b *IconButton) {
b.Tooltip = "Start new game"
}),
NewIconButtonConfigure("control-information", c.dialogs.ShowIntro, func(b *IconButton) {
b.Tooltip = "Show information/intro"
}),
}
for i, child := range c.menu.Children {
c.menu.Children[i] = ui.FixedHeight(child, 96)
}
c.shovel = NewIconButtonConfigure("control-shovel", func(ctx ui.Context) { c.game.SelectShovel(ctx) }, func(b *IconButton) {
b.Tooltip = "Select harvest tool (key: H)"
})
c.research = NewIconButtonConfigure("control-research", c.dialogs.ShowResearch, func(b *IconButton) {
b.Tooltip = "Conduct research (key: R)"
})
c.otherTools.Children = []ui.Control{c.shovel, c.research}
for i, child := range c.otherTools.Children {
c.otherTools.Children[i] = ui.FixedHeight(child, 96)
}
c.AddChild(&c.menu)
c.AddChild(&c.top)
c.AddChild(&c.flowers)
c.AddChild(&c.otherTools)
}
func (c *GameControls) createBuyFlowerButton(id string) *BuyFlowerButton {
flower, _ := c.game.Herbarium.Find(id)
return NewBuyFlowerButton(
flower.IconTemplate.Variant(1),
flower.IconTemplate.Disabled(),
id,
flower,
func(ctx ui.Context) {
c.game.SelectPlantFlowerTool(ctx, id)
},
)
}
func (c *GameControls) speedChanged(_ ui.Context, state interface{}) {
speed := state.(GameSpeed)
disable := func(b *IconButton, expected GameSpeed) {
b.Disabled = speed == expected
}
disable(c.pause, GameSpeedPaused)
disable(c.run, GameSpeedNormal)
disable(c.runFast, GameSpeedFast)
}
func (c *GameControls) toolChanged(_ ui.Context, state interface{}) {
tool, _ := state.(Tool)
var flowerID string
if tool, ok := tool.(*PlantFlowerTool); ok {
flowerID = tool.FlowerID
}
for _, control := range c.flowers.Children {
button := control.(*BuyFlowerButton)
button.Active = button.FlowerID == flowerID
button.Disabled = !c.game.Herbarium.IsUnlocked(button.FlowerID)
}
_, shovel := tool.(*ShovelTool)
c.shovel.Active = shovel
}
func (c *GameControls) updateFlowerControls() {
for _, b := range c.flowers.Children {
button := b.(*BuyFlowerButton)
flower, ok := c.game.Herbarium.Find(button.FlowerID)
if ok {
button.Update(flower)
}
}
}
const buttonBarWidth = 96
func (c *GameControls) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
c.ContainerBase.Arrange(ctx, bounds, offset, parent)
c.menu.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.Y, buttonBarWidth, bounds.Dy()), offset, c)
c.top.Arrange(ctx, geom.RectF32(bounds.Min.X+bounds.Dx()/2+8, bounds.Min.Y, bounds.Max.X, bounds.Min.Y+64), offset, c)
c.flowers.Arrange(ctx, geom.RectRelF32(bounds.Max.X-buttonBarWidth, bounds.Min.Y, buttonBarWidth, bounds.Dy()), offset, c)
otherToolsSize := c.otherTools.DesiredSize(ctx, bounds.Size())
c.otherTools.Arrange(ctx, geom.RectRelF32(bounds.Max.X-buttonBarWidth, bounds.Max.Y-otherToolsSize.Y, buttonBarWidth, 2*buttonBarWidth), offset, c)
}
func (c *GameControls) Handle(ctx ui.Context, event ui.Event) bool {
if c.ContainerBase.Handle(ctx, event) {
return true
}
switch e := event.(type) {
case *ui.KeyDownEvent:
switch e.Key {
case ui.KeySpace:
c.game.TogglePause(ctx)
case ui.Key1:
c.game.Run(ctx)
case ui.Key2:
c.game.RunFast(ctx)
case ui.KeyH:
c.game.SelectShovel(ctx)
case ui.KeyR:
c.dialogs.ShowResearch(ctx)
case ui.KeyEscape:
if c.game.Tool().Type() == "none" {
c.dialogs.ShowIntro(ctx)
} else {
c.game.CancelTool(ctx)
}
return true
case ui.KeyF4:
c.game.Debug = !c.game.Debug
ctx.Overlays().Toggle(fpsOverlayName)
}
if e.Modifiers == ui.KeyModifierControl {
switch e.Key {
case ui.KeyL:
c.askUserBeforeLoad(ctx)
case ui.KeyN:
c.askUserBeforeNew(ctx)
case ui.KeyS:
c.askUserBeforeSave(ctx)
}
}
}
return false
}
func (c *GameControls) Render(ctx ui.Context) {
topBar := zntg.MustHexColor("#0000007F")
ctx.Renderer().FillRectangle(geom.RectF32(c.menu.Bounds().Max.X, 0, c.flowers.Bounds().Min.X, 64), topBar)
ctx.Fonts().TextAlign("balance", geom.PtF32(c.top.Bounds().Min.X-8, 4), zntg.MustHexColor("#4AC69A"), FmtMoney(c.game.Balance), ui.AlignRight)
c.ContainerBase.Render(ctx)
}