Link various screens accessible from the bridge

This kind of linking is starting to creak...
This commit is contained in:
2020-03-27 02:07:28 +00:00
parent 316db89148
commit c090fd32e9
8 changed files with 133 additions and 27 deletions

View File

@@ -17,13 +17,13 @@ const (
TypeMenu MenuType = 1 TypeMenu MenuType = 1
TypeDragMenu MenuType = 2 // Only seen in Configure_Vehicle_{Chaos,Ultra} TypeDragMenu MenuType = 2 // Only seen in Configure_Vehicle_{Chaos,Ultra}
TypeSimpleButton MenuType = 3 TypeSimpleButton MenuType = 3
TypeDoorHotspot MenuType = 30 // Like a button I guess? FONTTYPE is animation speed TypeDoorHotspot MenuType = 30 // Like a button I guess? "FONTTYPE is animation speed"
TypeUnknown1 MenuType = 31 // ??? Needed for ChaEquip.mnu TypeDoorHotspot2 MenuType = 31 // Seems like a duplicate of the above? What's different?
TypeLineKbd MenuType = 40 TypeLineKbd MenuType = 40
TypeThumb MenuType = 45 TypeThumb MenuType = 45
TypeLineBriefing MenuType = 41 TypeLineBriefing MenuType = 41
TypeInvokeButton MenuType = 50 TypeInvokeButton MenuType = 50
TypeSquadButton MenuType = 60 // Maybe? Appears in Arrange.mnu TypeDoorHotspot3 MenuType = 60 // Maybe? Appears in Arrange.mnu
TypeOverlay MenuType = 61 TypeOverlay MenuType = 61
TypeHypertext MenuType = 70 TypeHypertext MenuType = 70
TypeCheckbox MenuType = 91 TypeCheckbox MenuType = 91

View File

@@ -3,9 +3,40 @@ package flow
func (f *Flow) linkBridge() { func (f *Flow) linkBridge() {
// FIXME: sometimes these doors are frozen, depending on game state // 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.1", f.setDriver(briefing)) // TODO: Mission briefing clickable
f.onClick(bridge, "2.2", f.setDriver(choices)) // Options door hotspot f.onClick(bridge, "2.2", f.setDriver(choices)) // Options door hotspot
f.setFreeze(bridge, "2.4", false) // FIXME: Enter combat 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.setFreeze(bridge, "2.6", false) // FIXME: Vehicle configure door hotspot
f.onClick(bridge, "2.8", f.setDriver(configureUltEquip)) // Squads configure door hotspot f.onClick(bridge, "2.8", f.setDriver(arrange)) // Squads configure door hotspot
// link children
f.linkChoices()
f.linkArrange()
}
func (f *Flow) linkChoices() {
f.onClick(choices, "2.1", f.setDriver(loadGame)) // Load another game button
f.onClick(choices, "2.2", f.setDriver(saveGame)) // Save this game button
f.onClick(choices, "2.3", f.setReturningDriver(choices, options)) // More options button
// FIXME: wipe out game state when this goes through
f.onClick(choices, "2.4", f.setDriver(main)) // Restart button
f.onClick(choices, "2.5", f.setDriver(credits)) // Credits button
f.onClick(choices, "2.6", f.setExit) // Quit button
f.onClick(choices, "2.7", f.setDriver(bridge)) // Back button
}
func (f *Flow) linkArrange() {
// FIXME: we should be operating on game data in here
f.onClick(arrange, "8.1", f.setDriver(bridge)) // Return to bridge ("cathedral")
f.onClick(arrange, "8.3", f.setDriver(configureUltEquip)) // Configure squads
f.linkConfigureUltEquip()
}
func (f *Flow) linkConfigureUltEquip() {
// FIXME: we should be modifying loadouts of selected squad members here
f.onClick(configureUltEquip, "8.1", f.setDriver(bridge)) // Return to bridge
} }

View File

@@ -2,6 +2,7 @@ package flow
import ( import (
"errors" "errors"
"fmt"
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
@@ -19,6 +20,13 @@ type Flow struct {
current *ui.Driver current *ui.Driver
drivers map[driverName]*ui.Driver drivers map[driverName]*ui.Driver
// Some screens can be returned to from more than one place. Where this is
// the case, instead of hardcoding it, we'll store an entry in here so we
// know where we're going back to
//
// FIXME: this really suggests wiring everything up at the start is wrong.
returns map[driverName]driverName
exit error exit error
} }
@@ -37,10 +45,12 @@ const (
bridge driverName = "Bridge" bridge driverName = "Bridge"
briefing driverName = "Briefing" briefing driverName = "Briefing"
choices driverName = "Choices" choices driverName = "Choices"
ultEquip driverName = "UltEquip" saveGame driverName = "SaveGame"
credits driverName = "Credits"
arrange driverName = "Arrange"
configureUltEquip driverName = "Configure_UltEquip" configureUltEquip driverName = "Configure_UltEquip"
configureVehiclesUltra driverName = "Configure_vehicles_ultra" configureVehiclesUltra driverName = "Configure_Vehicles_Ultra"
) )
var ( var (
@@ -48,8 +58,8 @@ var (
driverNames = []driverName{ driverNames = []driverName{
main, levelPly, singles, randomMap, newGame, loadGame, options, kbd, main, levelPly, singles, randomMap, newGame, loadGame, options, kbd,
bridge, briefing, choices, ultEquip, bridge, briefing, choices, saveGame, credits, arrange,
configureVehiclesUltra, configureUltEquip, configureVehiclesUltra,
} }
// Constants used for sliders // Constants used for sliders
@@ -74,6 +84,7 @@ func New(assets *assetstore.AssetStore, config *config.Config) (*Flow, error) {
assets: assets, assets: assets,
config: config, config: config,
drivers: make(map[driverName]*ui.Driver, len(driverNames)), drivers: make(map[driverName]*ui.Driver, len(driverNames)),
returns: make(map[driverName]driverName),
} }
// Load all the drivers upfront // Load all the drivers upfront
@@ -129,11 +140,11 @@ func (f *Flow) Draw(screen *ebiten.Image) error {
func (f *Flow) linkDrivers() { func (f *Flow) linkDrivers() {
// linkMain // linkMain
f.onClick(main, "2.1", f.setDriver(newGame)) // New game f.onClick(main, "2.1", f.setDriver(newGame)) // New game
f.onClick(main, "2.2", f.setDriver(loadGame)) // Load game f.onClick(main, "2.2", f.setDriver(loadGame)) // Load game
f.setFreeze(main, "2.3", true) // Multiplayer - disable for now f.setFreeze(main, "2.3", true) // Multiplayer - disable for now
f.onClick(main, "2.4", f.setDriver(options)) // Options f.onClick(main, "2.4", f.setReturningDriver(main, options)) // Options
f.onClick(main, "2.5", f.setExit) // Quit f.onClick(main, "2.5", f.setExit) // Quit
// Now link immediate children. They will link their children, and so on // Now link immediate children. They will link their children, and so on
f.linkNewGame() f.linkNewGame()
@@ -142,6 +153,14 @@ func (f *Flow) linkDrivers() {
f.linkOptions() f.linkOptions()
} }
func maybeErr(driver driverName, err error) error {
if err != nil {
return fmt.Errorf("%v: %v", driver, err)
}
return nil
}
func (f *Flow) configureSlider(driver driverName, id string, steps map[int]int) { func (f *Flow) configureSlider(driver driverName, id string, steps map[int]int) {
if f.exit != nil { if f.exit != nil {
return return
@@ -155,7 +174,7 @@ func (f *Flow) onClick(driver driverName, id string, fn func()) {
return return
} }
f.exit = f.drivers[driver].OnClick(id, fn) f.exit = maybeErr(driver, f.drivers[driver].OnClick(id, fn))
} }
func (f *Flow) setFreeze(driver driverName, id string, value bool) { func (f *Flow) setFreeze(driver driverName, id string, value bool) {
@@ -163,7 +182,7 @@ func (f *Flow) setFreeze(driver driverName, id string, value bool) {
return return
} }
f.exit = f.drivers[driver].SetFreeze(id, value) f.exit = maybeErr(driver, f.drivers[driver].SetFreeze(id, value))
} }
func (f *Flow) setValueBool(driver driverName, id string, value bool) { func (f *Flow) setValueBool(driver driverName, id string, value bool) {
@@ -184,6 +203,27 @@ func (f *Flow) setDriverNow(name driverName) {
f.current = f.drivers[name] f.current = f.drivers[name]
} }
// from is the parent menu, to is the child
func (f *Flow) setReturningDriver(from, to driverName) func() {
return func() {
f.returns[to] = from
f.setDriverNow(to)
}
}
// from is the child menu, to is the parent
func (f *Flow) returnToLastDriverNow(from driverName) error {
to, ok := f.returns[from]
if !ok {
return fmt.Errorf("Couldn't work out where to return to from %v", from)
}
delete(f.returns, from)
f.setDriverNow(to)
return nil
}
func (f *Flow) setExit() { func (f *Flow) setExit() {
f.exit = ErrExit f.exit = ErrExit
} }

View File

@@ -26,10 +26,13 @@ func (f *Flow) linkLevelPly() {
f.setDriverNow(newGame) f.setDriverNow(newGame)
}) })
// FIXME: we should select a savegame if Mighty Here is selected here // FIXME: we should select a savegame if Mighty Hero is selected here
// FIXME: we should show a movie here. Need an internal SMK player first // FIXME: we should show a movie here. Need an internal SMK player first
// FIXME: we should set up new game state here! // FIXME: we should set up new game state here!
f.onClick(levelPly, "2.7", f.setDriver(bridge)) // Select button f.onClick(levelPly, "2.7", f.setDriver(bridge)) // Select button
// Link children
f.linkBridge()
} }
func (f *Flow) linkSingles() { func (f *Flow) linkSingles() {

View File

@@ -44,7 +44,7 @@ func (f *Flow) cancelOptions() func() {
log.Printf("Saving options to config failed: %v", err) log.Printf("Saving options to config failed: %v", err)
f.exit = err f.exit = err
} else { } else {
f.setDriverNow(main) f.exit = f.returnToLastDriverNow(options)
} }
} }
} }

View File

@@ -11,7 +11,9 @@ func init() {
registerBuilder(menus.TypeSimpleButton, registerSimpleButton) registerBuilder(menus.TypeSimpleButton, registerSimpleButton)
registerBuilder(menus.TypeInvokeButton, registerInvokeButton) registerBuilder(menus.TypeInvokeButton, registerInvokeButton)
registerBuilder(menus.TypeMainButton, registerMainButton) registerBuilder(menus.TypeMainButton, registerMainButton)
registerBuilder(menus.TypeDoorHotspot, registerDebug("Unimplemented DoorHotspot", nil)) registerBuilder(menus.TypeDoorHotspot, registerDoorHotspot)
registerBuilder(menus.TypeDoorHotspot2, registerDoorHotspot)
registerBuilder(menus.TypeDoorHotspot3, registerDoorHotspot)
} }
// A button without hover animation // A button without hover animation
@@ -79,6 +81,29 @@ func registerMainButton(d *Driver, r *menus.Record) error {
return nil return nil
} }
func registerDoorHotspot(d *Driver, r *menus.Record) error {
sprites, err := d.menu.Sprites(r.Share, 2) // base, pressed
if err != nil {
return err
}
btn := &button{
path: r.Path(),
baseSpr: sprites[0],
clickSpr: sprites[1],
frozenSpr: sprites[0], // No disabled sprite
hoverImpl: hoverImpl{text: r.Text},
}
d.clickables = append(d.clickables, btn)
d.freezables = append(d.freezables, btn)
d.hoverables = append(d.hoverables, btn)
d.paintables = append(d.paintables, btn)
return nil
}
func registerButton(d *Driver, r *menus.Record, spriteId int) error { func registerButton(d *Driver, r *menus.Record, spriteId int) error {
sprites, err := d.menu.Sprites(spriteId, 3) // base, pressed, disabled sprites, err := d.menu.Sprites(spriteId, 3) // base, pressed, disabled
if err != nil { if err != nil {

View File

@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"image" "image"
"log" "log"
"runtime/debug"
"strconv" "strconv"
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
@@ -24,14 +25,10 @@ func init() {
registerBuilder(menus.TypeLineKbd, registerDebug("Unimplemented LineKbd", nil)) registerBuilder(menus.TypeLineKbd, registerDebug("Unimplemented LineKbd", nil))
registerBuilder(menus.TypeDialogue, registerDebug("Unimplemented Dialogue", nil)) registerBuilder(menus.TypeDialogue, registerDebug("Unimplemented Dialogue", nil))
// Needed for Arrange.mnu (???)
registerBuilder(menus.TypeSquadButton, registerDebug("Unimplemented SquadButton", nil))
// Needed for Briefing.mnu // Needed for Briefing.mnu
registerBuilder(menus.TypeLineBriefing, registerDebug("Unimplemented LineBriefing", nil)) registerBuilder(menus.TypeLineBriefing, registerDebug("Unimplemented LineBriefing", nil))
// Needed for ChaEquip.mnu // Needed for ChaEquip.mnu
registerBuilder(menus.TypeUnknown1, registerDebug("Unimplemented Unknown1", nil))
registerBuilder(menus.TypeThumb, registerDebug("Unimplemented Thumb", nil)) registerBuilder(menus.TypeThumb, registerDebug("Unimplemented Thumb", nil))
// Needed for MainGameChaos.mnu // Needed for MainGameChaos.mnu
@@ -226,6 +223,11 @@ func (d *Driver) SetValueInt(id string, value int) error {
} }
func (d *Driver) Update(screenX, screenY int) error { func (d *Driver) Update(screenX, screenY int) error {
if d == nil {
debug.PrintStack()
return fmt.Errorf("Tried to update a nil ui.Driver")
}
// This will be updated while processing hovers // This will be updated while processing hovers
d.tooltip = "" d.tooltip = ""
d.ticks += 1 d.ticks += 1
@@ -274,6 +276,11 @@ func (d *Driver) Update(screenX, screenY int) error {
} }
func (d *Driver) Draw(screen *ebiten.Image) error { func (d *Driver) Draw(screen *ebiten.Image) error {
if d == nil {
debug.PrintStack()
return fmt.Errorf("Tried to draw a nil ui.Driver")
}
var do ebiten.DrawImageOptions var do ebiten.DrawImageOptions
for _, paint := range d.paintables { for _, paint := range d.paintables {

View File

@@ -15,7 +15,7 @@ func init() {
registerBuilder(menus.TypeHypertext, registerHypertext) registerBuilder(menus.TypeHypertext, registerHypertext)
registerBuilder(menus.TypeOverlay, registerOverlay) registerBuilder(menus.TypeOverlay, registerOverlay)
registerBuilder(menus.TypeAnimationSample, registerAnimation) registerBuilder(menus.TypeAnimationSample, registerAnimation)
registerBuilder(menus.TypeAnimationHover, registerDebug("WIP AnimationHover", registerAnimationHover)) registerBuilder(menus.TypeAnimationHover, registerAnimationHover)
} }
// A non-interactive element is not a widget; it merely displays some pixels and // A non-interactive element is not a widget; it merely displays some pixels and