More work for MainGame.mnu

This commit is contained in:
2020-04-19 18:21:08 +01:00
parent f8828c95bd
commit 9be93b6091
12 changed files with 248 additions and 76 deletions

View File

@@ -241,9 +241,37 @@ func (f *Flow) playNextScenario(from driverName) func() {
} }
} }
func (f *Flow) setActive(driver driverName, id string, value bool) func() {
return func() {
if f.exit != nil {
return
}
f.exit = maybeErr(driver, f.setActiveNow(driver, id, value))
}
}
func (f *Flow) setActiveNow(driver driverName, id string, value bool) error {
return f.drivers[driver].SetActive(locator(driver, id), value)
}
func (f *Flow) toggleActive(driver driverName, id string) func() {
return func() {
if f.exit != nil {
return
}
f.exit = maybeErr(driver, f.drivers[driver].ToggleActive(locator(driver, id)))
}
}
func (f *Flow) showDialogue(driver driverName, id string) func() { func (f *Flow) showDialogue(driver driverName, id string) func() {
return func() { return func() {
f.drivers[driver].ShowDialogue(locator(driver, id)) if f.exit != nil {
return
}
f.exit = maybeErr(driver, f.drivers[driver].ShowDialogue(locator(driver, id)))
} }
} }

View File

@@ -4,13 +4,34 @@ package flow
// to duplicate everything for both? // to duplicate everything for both?
func (f *Flow) linkMainGame() { func (f *Flow) linkMainGame() {
// 3: Action menu // 3: Action menu. These are mostly predicated on selected character state
// 3.1: Aimed shot
// 3.2: Shooting
// 3.3: Walk
// 3.4: Run
// 3.5: Crouch/Stand
// 3.6: Hand to hand (commented out)
// 3.7: Retrieve
// 3.8: Door
// 3.9: Switch
// 3.10: Overwatch
// 3.11: Rally/Formation
// 3.12: Board/Disembark
// FIXME: for now, this is "end scenario", for convenience
f.onClick(mainGame, "3.13", func() { // End turn button.
f.scenario = nil
f.returnToLastDriverNow(mainGame)
})
// 3.14: Special action heal
// 3.15: Special action techmarine
// 3.16: Special action jump pack
// 3.17: Special action spell
// 4: Interface options menu // 4: Interface options menu
f.onClick(mainGame, "4.1", f.setReturningDriver(mainGame, options)) // Options button f.onClick(mainGame, "4.1", f.setReturningDriver(mainGame, options)) // Options button
// 4.2: Map button f.onClick(mainGame, "4.2", f.toggleActive(mainGame, "14")) // Map button
// 4.3: Mission objectives button // 4.3: Mission objectives button
// 4.4: Inventory f.onClick(mainGame, "4.4", f.showDialogue(mainGame, "12")) // Inventory
// 4.5: Next man // 4.5: Next man
// 4.6: Next enemy // 4.6: Next enemy
// 4.7: Total enemy text // 4.7: Total enemy text
@@ -22,31 +43,31 @@ func (f *Flow) linkMainGame() {
// 9: Visible enemy menu // 9: Visible enemy menu
// 10: Friendly squad menu // 10: Friendly squad menu
// 11: Psyker spell dialogue // 11: Psyker spell dialogue
// FIXME: lots and lots and lots of wiring up to do.
// For now, just link all the exit buttons to go back to the bridge
f.onClick(mainGame, "11.6", func() {
f.scenario = nil
f.returnToLastDriverNow(mainGame)
})
// 12: Inventory dialogue // 12: Inventory dialogue
f.onClick(mainGame, "12.21", func() { f.onClick(mainGame, "12.21", f.hideDialogue(mainGame)) // Exit
f.scenario = nil // 13: exchange menu
f.returnToLastDriverNow(mainGame)
})
// 13: Exchange menu
f.onClick(mainGame, "13.1", func() {
f.scenario = nil
f.returnToLastDriverNow(mainGame)
})
// 14: Map // 14: Map
// 14.1: MAP_SPRITE
// 14.2: Multiplier button (2x)
f.onClick(mainGame, "14.3", f.setActive(mainGame, "14", false))
// 14.4: Area
// 15: Interface wing left // FIXME: the display of left and right interface buttons is hidden by these
// 16: Interface wing right // sprites, because we draw in strict numeric order. Just hide them for now.
//
// FIXME: The child element is already set to hidden, while the menu itself
// is set to active, so maybe this is a hint that menus shouldn't be drawn?
//
// FIXME: the approach taken by the original binary in resolutions greater
// than 640x480 is to draw the menu elements *unscaled*. They are centered,
// and the dead space is filled by the "interface wing" sprites in the
// background. Should we replicate this, or keep with the current scaling
// behaviour? Which is better?
//
// FIXME: the menu bar should be at the bottom, not top, of the screen
f.exit = maybeErr(mainGame, f.setActiveNow(mainGame, "15", false)) // Interface wing left
f.exit = maybeErr(mainGame, f.setActiveNow(mainGame, "16", false)) // Interface wing right
// 17: Grenade dialogue // 17: Grenade dialogue
// 18: Info dialogue // 18: Info dialogue
// 19: Turn start dialogue // 19: Turn start dialogue

View File

@@ -44,6 +44,7 @@ func (d *Driver) buildButton(p *menus.Properties) (*button, *Widget, error) {
} }
widget := &Widget{ widget := &Widget{
Active: p.Active,
ownClickables: []clickable{btn}, ownClickables: []clickable{btn},
ownFreezables: []freezable{btn}, ownFreezables: []freezable{btn},
ownHoverables: []hoverable{btn}, ownHoverables: []hoverable{btn},
@@ -76,6 +77,7 @@ func (d *Driver) buildMainButton(p *menus.Properties) (*mainButton, *Widget, err
} }
widget := &Widget{ widget := &Widget{
Active: p.Active,
ownClickables: []clickable{btn}, ownClickables: []clickable{btn},
ownFreezables: []freezable{btn}, ownFreezables: []freezable{btn},
ownHoverables: []hoverable{btn}, ownHoverables: []hoverable{btn},
@@ -100,6 +102,7 @@ func (d *Driver) buildDoorHotspot(p *menus.Properties) (*button, *Widget, error)
} }
widget := &Widget{ widget := &Widget{
Active: p.Active,
ownClickables: []clickable{btn}, ownClickables: []clickable{btn},
ownFreezables: []freezable{btn}, ownFreezables: []freezable{btn},
ownHoverables: []hoverable{btn}, ownHoverables: []hoverable{btn},

View File

@@ -19,6 +19,7 @@ func (d *Driver) ShowDialogue(locator string) error {
if dialogue.Locator == locator { if dialogue.Locator == locator {
// FIXME: we should unhover and mouseup the non-dialogue elements // FIXME: we should unhover and mouseup the non-dialogue elements
dialogue.Active = true
d.activeDialogue = dialogue d.activeDialogue = dialogue
return nil return nil
@@ -28,5 +29,9 @@ func (d *Driver) ShowDialogue(locator string) error {
} }
func (d *Driver) HideDialogue() { func (d *Driver) HideDialogue() {
if d.activeDialogue != nil {
d.activeDialogue.Active = false
}
d.activeDialogue = nil d.activeDialogue = nil
} }

View File

@@ -169,11 +169,11 @@ func (d *Driver) allClickables() []clickable {
var out []clickable var out []clickable
for _, widget := range d.widgets { for _, widget := range d.widgets {
out = append(out, widget.clickables()...) out = append(out, widget.allClickables()...)
} }
for _, widget := range d.dialogues { for _, widget := range d.dialogues {
out = append(out, widget.clickables()...) out = append(out, widget.allClickables()...)
} }
return out return out
@@ -182,11 +182,11 @@ func (d *Driver) allClickables() []clickable {
func (d *Driver) allFreezables() []freezable { func (d *Driver) allFreezables() []freezable {
var out []freezable var out []freezable
for _, widget := range d.widgets { for _, widget := range d.widgets {
out = append(out, widget.freezables()...) out = append(out, widget.allFreezables()...)
} }
for _, widget := range d.dialogues { for _, widget := range d.dialogues {
out = append(out, widget.freezables()...) out = append(out, widget.allFreezables()...)
} }
return out return out
@@ -196,11 +196,11 @@ func (d *Driver) allValueables() []valueable {
var out []valueable var out []valueable
for _, widget := range d.widgets { for _, widget := range d.widgets {
out = append(out, widget.valueables()...) out = append(out, widget.allValueables()...)
} }
for _, widget := range d.dialogues { for _, widget := range d.dialogues {
out = append(out, widget.valueables()...) out = append(out, widget.allValueables()...)
} }
return out return out
@@ -208,12 +208,12 @@ func (d *Driver) allValueables() []valueable {
func (d *Driver) activeClickables() []clickable { func (d *Driver) activeClickables() []clickable {
if d.activeDialogue != nil { if d.activeDialogue != nil {
return d.activeDialogue.clickables() return d.activeDialogue.activeClickables()
} }
var out []clickable var out []clickable
for _, widget := range d.widgets { for _, widget := range d.widgets {
out = append(out, widget.clickables()...) out = append(out, widget.activeClickables()...)
} }
return out return out
@@ -221,12 +221,12 @@ func (d *Driver) activeClickables() []clickable {
func (d *Driver) activeHoverables() []hoverable { func (d *Driver) activeHoverables() []hoverable {
if d.activeDialogue != nil { if d.activeDialogue != nil {
return d.activeDialogue.hoverables() return d.activeDialogue.activeHoverables()
} }
var out []hoverable var out []hoverable
for _, widget := range d.widgets { for _, widget := range d.widgets {
out = append(out, widget.hoverables()...) out = append(out, widget.activeHoverables()...)
} }
return out return out
@@ -234,12 +234,12 @@ func (d *Driver) activeHoverables() []hoverable {
func (d *Driver) activeMouseables() []mouseable { func (d *Driver) activeMouseables() []mouseable {
if d.activeDialogue != nil { if d.activeDialogue != nil {
return d.activeDialogue.mouseables() return d.activeDialogue.activeMouseables()
} }
var out []mouseable var out []mouseable
for _, widget := range d.widgets { for _, widget := range d.widgets {
out = append(out, widget.mouseables()...) out = append(out, widget.activeMouseables()...)
} }
return out return out
@@ -249,12 +249,23 @@ func (d *Driver) activePaintables() []paintable {
var out []paintable var out []paintable
for _, widget := range d.widgets { for _, widget := range d.widgets {
out = append(out, widget.paintables()...) out = append(out, widget.activePaintables()...)
} }
if d.activeDialogue != nil { if d.activeDialogue != nil {
out = append(out, d.activeDialogue.paintables()...) out = append(out, d.activeDialogue.activePaintables()...)
} }
return out return out
} }
func (d *Driver) findWidget(locator string) *Widget {
toplevels := append(d.widgets, d.dialogues...)
for _, widget := range toplevels {
if w := widget.findWidget(locator); w != nil {
return w
}
}
return nil
}

View File

@@ -28,7 +28,10 @@ func (d *Driver) registerGroup(group *menus.Group) error {
return err return err
} }
} else { } else {
groupWidget = &Widget{Locator: group.Locator} groupWidget = &Widget{
Locator: group.Locator,
Active: group.Active,
}
} }
if dialogue { if dialogue {
@@ -127,6 +130,7 @@ func (d *Driver) maybeBuildInventorySelect(group *menus.Group, records []*menus.
elements := make([]*inventorySelect, len(touched)) elements := make([]*inventorySelect, len(touched))
widget := &Widget{ widget := &Widget{
Locator: group.Locator, Locator: group.Locator,
Active: group.Active,
} }
for i, record := range touched { for i, record := range touched {

View File

@@ -27,6 +27,7 @@ func (d *Driver) buildInventorySelect(p *menus.Properties) (*inventorySelect, *W
element := &inventorySelect{checkbox: *c} element := &inventorySelect{checkbox: *c}
widget := &Widget{ widget := &Widget{
Active: p.Active,
ownClickables: []clickable{element}, ownClickables: []clickable{element},
ownFreezables: []freezable{element}, ownFreezables: []freezable{element},
ownHoverables: []hoverable{element}, ownHoverables: []hoverable{element},

View File

@@ -77,6 +77,7 @@ func (d *Driver) buildListBox(group *menus.Group, up, down, thumb *menus.Record,
// mostly self-registered at the moment. // mostly self-registered at the moment.
widget := &Widget{ widget := &Widget{
Children: []*Widget{upWidget, downWidget}, Children: []*Widget{upWidget, downWidget},
Active: group.Active, // FIXME: children have their own active state
ownPaintables: []paintable{element}, ownPaintables: []paintable{element},
ownValueables: []valueable{element}, ownValueables: []valueable{element},
} }

View File

@@ -83,6 +83,7 @@ func (d *Driver) buildStatic(p *menus.Properties) (*noninteractive, *Widget, err
widget := &Widget{ widget := &Widget{
Locator: ni.locator, Locator: ni.locator,
Active: p.Active,
ownClickables: []clickable{ni}, // FIXME: credits background needs to be clickable ownClickables: []clickable{ni}, // FIXME: credits background needs to be clickable
ownHoverables: []hoverable{ni}, ownHoverables: []hoverable{ni},
ownPaintables: []paintable{ni}, ownPaintables: []paintable{ni},
@@ -100,6 +101,7 @@ func (d *Driver) buildHypertext(p *menus.Properties) (*noninteractive, *Widget,
// FIXME: check if this is still needed on the bridge -> briefing transition // FIXME: check if this is still needed on the bridge -> briefing transition
widget := &Widget{ widget := &Widget{
Locator: ni.locator, Locator: ni.locator,
Active: p.Active,
ownClickables: []clickable{ni}, ownClickables: []clickable{ni},
ownHoverables: []hoverable{ni}, ownHoverables: []hoverable{ni},
} }
@@ -116,6 +118,7 @@ func (d *Driver) buildOverlay(p *menus.Properties) (*noninteractive, *Widget, er
widget := &Widget{ widget := &Widget{
Locator: ni.locator, Locator: ni.locator,
Active: p.Active,
ownPaintables: []paintable{ni}, ownPaintables: []paintable{ni},
} }
@@ -155,6 +158,7 @@ func (d *Driver) buildAnimationSample(p *menus.Properties) (*noninteractive, *Wi
} }
widget := &Widget{ widget := &Widget{
Active: p.Active,
ownHoverables: []hoverable{ani}, ownHoverables: []hoverable{ani},
ownPaintables: []paintable{ani}, ownPaintables: []paintable{ani},
} }
@@ -190,6 +194,7 @@ func (d *Driver) buildAnimationHover(p *menus.Properties) (*animationHover, *Wid
} }
widget := &Widget{ widget := &Widget{
Active: p.Active,
ownHoverables: []hoverable{ani}, ownHoverables: []hoverable{ani},
ownPaintables: []paintable{ani}, ownPaintables: []paintable{ani},
} }

View File

@@ -51,6 +51,8 @@ func (d *Driver) buildCheckbox(p *menus.Properties) (*checkbox, *Widget, error)
} }
widget := &Widget{ widget := &Widget{
Locator: p.Locator,
Active: p.Active,
ownClickables: []clickable{checkbox}, ownClickables: []clickable{checkbox},
ownFreezables: []freezable{checkbox}, ownFreezables: []freezable{checkbox},
ownHoverables: []hoverable{checkbox}, ownHoverables: []hoverable{checkbox},
@@ -76,6 +78,8 @@ func (d *Driver) buildSlider(p *menus.Properties) (*slider, *Widget, error) {
} }
widget := &Widget{ widget := &Widget{
Locator: p.Locator,
Active: p.Active,
ownClickables: []clickable{slider}, ownClickables: []clickable{slider},
ownMouseables: []mouseable{slider}, ownMouseables: []mouseable{slider},
ownPaintables: []paintable{slider}, ownPaintables: []paintable{slider},

View File

@@ -61,6 +61,26 @@ func (d *Driver) SetFreeze(id string, value bool) error {
return fmt.Errorf("Couldn't find clickable widget %v:%v", d.menu.Name, id) return fmt.Errorf("Couldn't find clickable widget %v:%v", d.menu.Name, id)
} }
func (d *Driver) ToggleActive(locator string) error {
if widget := d.findWidget(locator); widget != nil {
widget.Active = !widget.Active
return nil
}
return fmt.Errorf("Couldn't find activatable widget %v to toggle", locator)
}
func (d *Driver) SetActive(locator string, value bool) error {
if widget := d.findWidget(locator); widget != nil {
widget.Active = value
return nil
}
return fmt.Errorf("Couldn't find activeatable widget %v to set to %v", locator, value)
}
func (d *Driver) OnClick(id string, f func()) error { func (d *Driver) OnClick(id string, f func()) error {
for _, clickable := range d.allClickables() { for _, clickable := range d.allClickables() {
if clickable.id() == d.realId(id) { if clickable.id() == d.realId(id) {

View File

@@ -3,6 +3,7 @@ package ui
type Widget struct { type Widget struct {
Locator string Locator string
Children []*Widget Children []*Widget
Active bool
ownClickables []clickable ownClickables []clickable
ownFreezables []freezable ownFreezables []freezable
@@ -12,62 +13,130 @@ type Widget struct {
ownValueables []valueable ownValueables []valueable
} }
func (w *Widget) clickables() []clickable { func (w *Widget) allClickables() []clickable {
out := w.ownClickables out := w.ownClickables
for _, widget := range w.Children { for _, widget := range w.Children {
out = append(out, widget.clickables()...) out = append(out, widget.allClickables()...)
} }
return out return out
} }
func (w *Widget) freezables() []freezable { func (w *Widget) allFreezables() []freezable {
out := w.ownFreezables out := w.ownFreezables
for _, widget := range w.Children { for _, widget := range w.Children {
out = append(out, widget.freezables()...) out = append(out, widget.allFreezables()...)
} }
return out return out
} }
func (w *Widget) hoverables() []hoverable { func (w *Widget) allValueables() []valueable {
out := w.ownHoverables
for _, widget := range w.Children {
out = append(out, widget.hoverables()...)
}
return out
}
func (w *Widget) mouseables() []mouseable {
out := w.ownMouseables
for _, widget := range w.Children {
out = append(out, widget.mouseables()...)
}
return out
}
func (w *Widget) paintables() []paintable {
out := w.ownPaintables
for _, widget := range w.Children {
out = append(out, widget.paintables()...)
}
return out
}
func (w *Widget) valueables() []valueable {
out := w.ownValueables out := w.ownValueables
for _, widget := range w.Children { for _, widget := range w.Children {
out = append(out, widget.valueables()...) out = append(out, widget.allValueables()...)
} }
return out return out
} }
func (w *Widget) activeClickables() []clickable {
if !w.Active {
return nil
}
out := w.ownClickables
for _, widget := range w.Children {
out = append(out, widget.activeClickables()...)
}
return out
}
func (w *Widget) activeFreezables() []freezable {
if !w.Active {
return nil
}
out := w.ownFreezables
for _, widget := range w.Children {
out = append(out, widget.activeFreezables()...)
}
return out
}
func (w *Widget) activeHoverables() []hoverable {
if !w.Active {
return nil
}
out := w.ownHoverables
for _, widget := range w.Children {
out = append(out, widget.activeHoverables()...)
}
return out
}
func (w *Widget) activeMouseables() []mouseable {
if !w.Active {
return nil
}
out := w.ownMouseables
for _, widget := range w.Children {
out = append(out, widget.activeMouseables()...)
}
return out
}
func (w *Widget) activePaintables() []paintable {
if !w.Active {
return nil
}
out := w.ownPaintables
for _, widget := range w.Children {
out = append(out, widget.activePaintables()...)
}
return out
}
func (w *Widget) activeValueables() []valueable {
if !w.Active {
return nil
}
out := w.ownValueables
for _, widget := range w.Children {
out = append(out, widget.activeValueables()...)
}
return out
}
func (w *Widget) findWidget(locator string) *Widget {
if w.Locator == locator {
return w
}
for _, child := range w.Children {
if found := child.findWidget(locator); found != nil {
return found
}
}
return nil
}