Display MainGame.mnu and map in ordoor simultaneously

It's a complete mess for now - many things are out of place or shown
when they shouldn't be - and we can't move around the game map. But,
it's a good start.
This commit is contained in:
2020-04-11 01:01:05 +01:00
parent 5f8606377a
commit 76bf8438b0
9 changed files with 176 additions and 77 deletions

View File

@@ -245,13 +245,14 @@ observed, suggesting structure. For instance, we have `24`, `240`, `241` and
`2410`, but not `2411` or `2409`. Sometimes we have a comma-separated list,
e.g.: `400,30,-1,5`.
A listing of currently-known values:
A listing of some currently-known values:
| Value | Type |
| ----- | ---------------- |
| 0 | Static image |
| 1 | Menu |
| 3 | Button |
| 45 | Thumb |
| 50 | Invoke? Button? |
| 61 | "Overlay" |
| 70 | "Hypertext" |
@@ -260,6 +261,13 @@ A listing of currently-known values:
| 228 | Main menu button |
| 232 | Slider |
Hypothesis: `MENUTYPE` and `SUBMENUTYPE` are actually distinct lists of values.
So far, I've been treating them as the same thing, but, e.g., `MainGame.mnu` has
a `MENUTYPE: 45` which is labelled "MAIN BACKGROUND", while `SUBMENUTYPE: 45`
is tentatively labelled a "thumb" and used in text boxes. There are also a few
cases where I've had to manually override the `MENUTYPE` because it coincides
with `Button`.
### `ACTIVE`
There are only 4 values seen across all menus: `0`, `1`, `1,0`, `102` and `1,1`.

View File

@@ -4,15 +4,16 @@ func (f *Flow) linkBridge() {
// FIXME: sometimes these doors are frozen, depending on ship state, but we
// don't implement that yet.
f.onClick(bridge, "2.1", f.setDriver(briefing)) // Mission briefing clickable
f.onClick(bridge, "2.2", f.setDriver(choices)) // Options door hotspot
f.onClick(bridge, "2.4", f.playNextScenario()) // Enter combat door hotspot
f.setFreeze(bridge, "2.6", true) // TODO: Vehicle configure door hotspot
f.onClick(bridge, "2.8", f.setDriver(arrange)) // Squads configure door hotspot
f.onClick(bridge, "2.1", f.setDriver(briefing)) // Mission briefing clickable
f.onClick(bridge, "2.2", f.setDriver(choices)) // Options door hotspot
f.onClick(bridge, "2.4", f.playNextScenario(bridge)) // Enter combat door hotspot
f.setFreeze(bridge, "2.6", true) // TODO: Vehicle configure door hotspot
f.onClick(bridge, "2.8", f.setDriver(arrange)) // Squads configure door hotspot
// link children
f.linkBriefing()
f.linkChoices()
f.linkMainGame()
f.linkArrange()
}

74
internal/flow/drivers.go Normal file
View File

@@ -0,0 +1,74 @@
package flow
import (
"fmt"
)
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"
briefing driverName = "Briefing"
choices driverName = "Choices"
saveGame driverName = "SaveGame"
credits driverName = "Credits"
arrange driverName = "Arrange"
configureUltEquip driverName = "Configure_UltEquip"
configureVehiclesUltra driverName = "Configure_Vehicles_Ultra"
mainGame driverName = "MainGame"
)
var (
driverNames = []driverName{
main, levelPly, singles, randomMap, newGame, loadGame, options, kbd,
bridge, briefing, choices, saveGame, credits, arrange,
configureUltEquip, configureVehiclesUltra,
mainGame,
}
)
// 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) setDriver(name driverName) func() {
return func() {
f.setDriverNow(name)
}
}
func (f *Flow) setDriverNow(name driverName) {
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.setReturningDriverNow(from, to)
}
}
func (f *Flow) setReturningDriverNow(from, to driverName) {
f.returns[to] = from
f.setDriverNow(to)
}

View File

@@ -40,38 +40,9 @@ type Flow struct {
exit error
}
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"
briefing driverName = "Briefing"
choices driverName = "Choices"
saveGame driverName = "SaveGame"
credits driverName = "Credits"
arrange driverName = "Arrange"
configureUltEquip driverName = "Configure_UltEquip"
configureVehiclesUltra driverName = "Configure_Vehicles_Ultra"
)
var (
ErrExit = errors.New("exiting gracefully")
driverNames = []driverName{
main, levelPly, singles, randomMap, newGame, loadGame, options, kbd,
bridge, briefing, choices, saveGame, credits, arrange,
configureUltEquip, configureVehiclesUltra,
}
// Constants used for sliders
h3Slider = map[int]int{1: 8, 2: 56, 3: 110, 4: 120}
@@ -245,25 +216,7 @@ func (f *Flow) setValueBool(driver driverName, id string, value bool) {
f.exit = f.drivers[driver].SetValueBool(id, value)
}
func (f *Flow) setDriver(name driverName) func() {
return func() {
f.setDriverNow(name)
}
}
func (f *Flow) setDriverNow(name driverName) {
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)
}
}
func (f *Flow) playNextScenario() func() {
func (f *Flow) playNextScenario(from driverName) func() {
return func() {
log.Printf("Loading scenario: %v", f.ship.NextScenario)
@@ -275,24 +228,11 @@ func (f *Flow) playNextScenario() func() {
return
}
f.current = nil // TODO: show the UI for a scenario
f.setReturningDriverNow(from, mainGame)
f.scenario = scenario
}
}
// 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() {
f.exit = ErrExit
}

View File

@@ -0,0 +1,55 @@
package flow
// TODO: There are Chaos and Ultramarine versions of MainGame. Do we really want
// to duplicate everything for both?
func (f *Flow) linkMainGame() {
// 3: Action menu
// 4: Interface options menu
f.onClick(mainGame, "4.1", f.setReturningDriver(mainGame, options)) // Options button
// 4.2: Map button
// 4.3: Mission objectives button
// 4.4: Inventory
// 4.5: Next man
// 4.6: Next enemy
// 4.7: Total enemy text
// 5: Holding menu
// 6: View menu
// 7: General character menu
// 8: Character stats
// 9: Visible enemy menu
// 10: Friendly squad menu
// 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
f.onClick(mainGame, "12.21", func() {
f.scenario = nil
f.returnToLastDriverNow(mainGame)
})
// 13: Exchange menu
f.onClick(mainGame, "13.1", func() {
f.scenario = nil
f.returnToLastDriverNow(mainGame)
})
// 14: Map
// 15: Interface wing left
// 16: Interface wing right
// 17: Grenade dialogue
// 18: Info dialogue
// 19: Turn start dialogue
// 20: Chat menu
// 21: Chat list menu box
}

View File

@@ -65,11 +65,16 @@ var TextOverrides = map[string]string{
// FIXME: The menu is specified as type 2 (button) in these cases, which is
// weird. Make it a menu for now.
//
// Hypothesis: MENUTYPE and SUBMENUTYPE are not equivalent?
var TypeOverrides = map[string]MenuType{
"levelply:2": TypeMenu,
"savegame:2": TypeMenu,
"loadgame:2": TypeMenu,
// "thumb" is not a background.
"maingame:2": TypeStatic,
// ???
"configure_ultequip:7.5": TypeListBoxUp,
"configure_ultequip:7.6": TypeListBoxDown,

View File

@@ -327,7 +327,7 @@ func (d *Driver) Cursor() (*ebiten.Image, *ebiten.DrawImageOptions, error) {
}
func (d *Driver) addRecord(record *menus.Record) error {
//log.Printf("Adding record: %#+v", record)
log.Printf("Adding record %v: %#+v", record.Locator(), record)
children := record.Children
handler, ok := widgetBuilders[record.Type]

View File

@@ -45,6 +45,7 @@ func registerListBox(d *Driver, menu *menus.Record) ([]*menus.Record, error) {
var downBtn *menus.Record
var thumb *menus.Record
var items []*menus.Record
var otherChildren []*menus.Record
for _, rec := range menu.Children {
switch rec.Type {
@@ -66,7 +67,8 @@ func registerListBox(d *Driver, menu *menus.Record) ([]*menus.Record, error) {
}
thumb = rec
default:
return nil, fmt.Errorf("Unrecognised child in listbox menu: %v", rec.Locator())
// e.g. maingame:18.12 includes a button that is not part of the box
otherChildren = append(otherChildren, rec)
}
}
@@ -80,12 +82,21 @@ func registerListBox(d *Driver, menu *menus.Record) ([]*menus.Record, error) {
return nil, err
}
elemUp, err := registerButton(d, upBtn, upBtn.SpriteId[0])
upSprId := upBtn.SpriteId[0]
if upSprId == -1 {
upSprId = upBtn.Share
}
elemUp, err := registerButton(d, upBtn, upSprId)
if err != nil {
return nil, err
}
elemDown, err := registerButton(d, downBtn, downBtn.SpriteId[0])
dnSprId := downBtn.SpriteId[0]
if dnSprId == -1 {
dnSprId = downBtn.Share
}
elemDown, err := registerButton(d, downBtn, dnSprId)
if err != nil {
return nil, err
}
@@ -95,7 +106,12 @@ func registerListBox(d *Driver, menu *menus.Record) ([]*menus.Record, error) {
return nil, err
}
thumbImgSpr, err := d.menu.Sprite(thumb.SpriteId[0])
thumbSprId := thumb.SpriteId[0]
if thumbSprId == -1 {
thumbSprId = thumb.Share
}
thumbImgSpr, err := d.menu.Sprite(thumbSprId)
if err != nil {
return nil, err
}
@@ -145,7 +161,7 @@ func registerListBox(d *Driver, menu *menus.Record) ([]*menus.Record, error) {
element.refresh()
return nil, nil
return otherChildren, nil
}
func (l *listBox) SetStrings(to []string) {

View File

@@ -16,7 +16,7 @@ const (
)
func init() {
registerBuilder(menus.TypeStatic, noChildren(registerStatic))
registerBuilder(menus.TypeStatic, registerStatic) // MainGame has a hypertext child
registerBuilder(menus.TypeHypertext, noChildren(registerHypertext))
registerBuilder(menus.TypeOverlay, noChildren(registerOverlay))
registerBuilder(menus.TypeAnimationSample, noChildren(registerAnimation))
@@ -58,9 +58,9 @@ type animationHover struct {
closing bool
}
func registerStatic(d *Driver, r *menus.Record) error {
func registerStatic(d *Driver, r *menus.Record) ([]*menus.Record, error) {
_, err := registerNoninteractive(d, r)
return err
return r.Children, err
}
func registerNoninteractive(d *Driver, r *menus.Record) (*noninteractive, error) {