From 316db89148381af854e8643ca41c172bf39e0c5a Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Fri, 27 Mar 2020 00:54:57 +0000 Subject: [PATCH] Get the bridge door animations running --- internal/menus/menus.go | 2 +- internal/ordoor/flow/bridge.go | 11 +++++ internal/ordoor/flow/flow.go | 27 +++++++----- internal/ui/buttons.go | 1 + internal/ui/driver.go | 4 -- internal/ui/noninteractive.go | 76 ++++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 internal/ordoor/flow/bridge.go diff --git a/internal/menus/menus.go b/internal/menus/menus.go index f6a362c..f94fbca 100644 --- a/internal/menus/menus.go +++ b/internal/menus/menus.go @@ -33,7 +33,7 @@ const ( TypeDropdownButton MenuType = 200 TypeComboBoxItem MenuType = 205 TypeAnimationSample MenuType = 220 - TypeAnimationToo MenuType = 221 // No idea why we have two of these. FONTTYPE is animation speed. + TypeAnimationHover MenuType = 221 // FONTTYPE is animation speed. Only animate when hovered TypeMainButton MenuType = 228 TypeSlider MenuType = 232 TypeStatusBar MenuType = 233 diff --git a/internal/ordoor/flow/bridge.go b/internal/ordoor/flow/bridge.go new file mode 100644 index 0000000..9dadf08 --- /dev/null +++ b/internal/ordoor/flow/bridge.go @@ -0,0 +1,11 @@ +package flow + +func (f *Flow) linkBridge() { + // FIXME: sometimes these doors are frozen, depending on game state + + f.onClick(bridge, "2.1", f.setDriver(briefing)) // Mission briefing clickable + f.onClick(bridge, "2.2", f.setDriver(choices)) // Options door hotspot + f.setFreeze(bridge, "2.4", false) // FIXME: Enter combat door hotspot (!!!) + f.onClick(bridge, "2.6", f.setDriver(configureVehiclesUltra)) // Vehicle configure door hotspot + f.onClick(bridge, "2.8", f.setDriver(configureUltEquip)) // Squads configure door hotspot +} diff --git a/internal/ordoor/flow/flow.go b/internal/ordoor/flow/flow.go index fd78ddc..dc792c6 100644 --- a/internal/ordoor/flow/flow.go +++ b/internal/ordoor/flow/flow.go @@ -26,15 +26,21 @@ type driverName string const ( // Names of all the drivers - main driverName = "main" - levelPly driverName = "levelPly" - singles driverName = "singles" - randomMap driverName = "randomMap" - newGame driverName = "newGame" - loadGame driverName = "loadGame" - options driverName = "options" - kbd driverName = "keyboard" - bridge driverName = "bridge" + main driverName = "Main" + levelPly driverName = "LevelPly" + singles driverName = "Singles" + randomMap driverName = "RandomMap" + newGame driverName = "NewGame" + loadGame driverName = "LoadGame" + options driverName = "Options" + kbd driverName = "Keyboard" + bridge driverName = "Bridge" + briefing driverName = "Briefing" + choices driverName = "Choices" + ultEquip driverName = "UltEquip" + + configureUltEquip driverName = "Configure_UltEquip" + configureVehiclesUltra driverName = "Configure_vehicles_ultra" ) var ( @@ -42,7 +48,8 @@ var ( driverNames = []driverName{ main, levelPly, singles, randomMap, newGame, loadGame, options, kbd, - bridge, + bridge, briefing, choices, ultEquip, + configureVehiclesUltra, } // Constants used for sliders diff --git a/internal/ui/buttons.go b/internal/ui/buttons.go index 59cb6ee..6724cb9 100644 --- a/internal/ui/buttons.go +++ b/internal/ui/buttons.go @@ -11,6 +11,7 @@ func init() { registerBuilder(menus.TypeSimpleButton, registerSimpleButton) registerBuilder(menus.TypeInvokeButton, registerInvokeButton) registerBuilder(menus.TypeMainButton, registerMainButton) + registerBuilder(menus.TypeDoorHotspot, registerDebug("Unimplemented DoorHotspot", nil)) } // A button without hover animation diff --git a/internal/ui/driver.go b/internal/ui/driver.go index 1e29b6d..486a22d 100644 --- a/internal/ui/driver.go +++ b/internal/ui/driver.go @@ -26,10 +26,6 @@ func init() { // Needed for Arrange.mnu (???) registerBuilder(menus.TypeSquadButton, registerDebug("Unimplemented SquadButton", nil)) - registerBuilder(menus.TypeAnimationToo, registerDebug("Unimplemented AnimationToo", nil)) - - // Needed for Bridge.mnu - registerBuilder(menus.TypeDoorHotspot, registerDebug("Unimplemented DoorHotspot", nil)) // Needed for Briefing.mnu registerBuilder(menus.TypeLineBriefing, registerDebug("Unimplemented LineBriefing", nil)) diff --git a/internal/ui/noninteractive.go b/internal/ui/noninteractive.go index 3f74227..c09dd75 100644 --- a/internal/ui/noninteractive.go +++ b/internal/ui/noninteractive.go @@ -15,6 +15,7 @@ func init() { registerBuilder(menus.TypeHypertext, registerHypertext) registerBuilder(menus.TypeOverlay, registerOverlay) registerBuilder(menus.TypeAnimationSample, registerAnimation) + registerBuilder(menus.TypeAnimationHover, registerDebug("WIP AnimationHover", registerAnimationHover)) } // A non-interactive element is not a widget; it merely displays some pixels and @@ -31,6 +32,17 @@ type noninteractive struct { hoverImpl } +// This particular animation has entry and exit sequences, which are invoked +// when entering and leaving hover, respectively. Example: bridge doors +type animationHover struct { + noninteractive // Use the frames in here for the "enter hover" animation + exitFrames animation // and here the "exit hover" animation + + atTick int // Tracks progress through the frames + opening bool + closing bool +} + func registerStatic(d *Driver, r *menus.Record) error { // FIXME: SpriteID takes precedence over SHARE if present, but is that right? spriteId := r.Share @@ -125,6 +137,38 @@ func registerAnimation(d *Driver, r *menus.Record) error { return nil } +func registerAnimationHover(d *Driver, r *menus.Record) error { + sprite, err := d.menu.Sprite(r.SpriteId[0]) + if err != nil { + return err + } + + enterFrames, err := d.menu.Images(r.SpriteId[0], r.DrawType) + if err != nil { + return err + } + + exitFrames, err := d.menu.Images(r.SpriteId[0]+r.DrawType, r.DrawType) + if err != nil { + return err + } + + ani := &animationHover{ + noninteractive: noninteractive{ + frames: animation(enterFrames), + hoverImpl: hoverImpl{text: r.Text}, + rect: sprite.Rect, + }, + + exitFrames: animation(exitFrames), + } + + d.hoverables = append(d.hoverables, ani) + d.paintables = append(d.paintables, ani) + + return nil +} + func (n *noninteractive) bounds() image.Rectangle { return n.rect } @@ -138,3 +182,35 @@ func (n *noninteractive) regions(tick int) []region { return out } + +func (a *animationHover) regions(tick int) []region { + if a.opening || a.closing { + var anim animation + if a.opening { + anim = a.frames + } else { + anim = a.exitFrames + } + + out := oneRegion(a.bounds().Min, anim[a.atTick]) + + if a.atTick < len(anim)-1 { + a.atTick += 1 + } else if !a.hoverState() { + a.closing = false + } + + return out + } + + // Nothing doing, show a closed door + return oneRegion(a.bounds().Min, a.frames.image(0)) +} + +func (a *animationHover) setHoverState(value bool) { + a.atTick = 0 + a.opening = value + a.closing = !value + + a.hoverImpl.setHoverState(value) +}