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 (key: Ctrl+S)" }), NewIconButtonConfigure("control-load", c.askUserBeforeLoad, func(b *IconButton) { b.Tooltip = "Load last saved game (key: Ctrl+L)" }), NewIconButtonConfigure("control-new", c.askUserBeforeNew, func(b *IconButton) { b.Tooltip = "Start new game (key: Ctrl+N)" }), NewIconButtonConfigure("control-information", c.dialogs.ShowIntro, func(b *IconButton) { b.Tooltip = "Show information/intro (key: Escape)" }), } 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) }