Files
ordoor/doc/formats/mnu.md
Nick Thomas 786d261f98 Allow dialogues to be hidden or shown
To do this, MENU and SUBMENU are split into two types (at last), and
a Widget type is introduced. This should allow lots of code to be
removed at some point.
2020-04-14 03:14:49 +01:00

9.0 KiB

*.mnu

These files appear to be the UI definitions for Chaos Gate. Some relate to system menus, other to in-game menus. Their names are hardcoded into the WH40K.exe binary. Each has a .obj file associated with it.

It's an ASCII-formatted text file with a 12-line header, followed by a number of descriptor records.

Here's the top of MainGame.mnu:

MainGame.obj
BACKGROUND COLOR 0..255..-1 trans : 0
HYPERTEXT COLOR 0..255            : 120
FONT TYPE 0..5                    : 10
wh40k_12
basfnt12
wh40k_47
wh40k_12_red
wh40k_12_blue
wh40k_12_green
wh40k_12_yellow
NULL

The first line of the header is a .obj file containing sprites we want to display on-screen. We see entries further down have a SPRITEID, which must reference entries in that file.

In SaveGame.mnu, we can see multiple .obj files can be referenced.

There are then 3 lines that seem to be fixed descriptor names with values that vary. Is this font colour, perhaps? Unsure.

Next is a variable-length list of font names, referencing files in the Fonts directory.

Finally, there's a list of records that specify the menu itself. Truncated contents of SaveGame.mnu:

#rem..........Background
MENUID     : 1
MENUTYPE   : 0
MOVEABLE   : 0
ACTIVE     : 1
SPRITEID   : 0
ACCELERATOR: 0
DRAW TYPE  : 0
SHARE      : -1
X-CORD     : -1
Y-CORD     : -1
DESC       :
*
#rem..........MAIN BACKGROUND
MENUID     : 2
MENUTYPE   : 45
MOVEABLE   : 0
ACTIVE     : 1
SPRITEID   : 0
ACCELERATOR: 0
DRAW TYPE  : 0
SHARE      : -1
X-CORD     : -1
Y-CORD     : -1
DESC       :
#rem.......... MAIN BACKGROUND
        SUBMENUID  : 1
        SUBMENUTYPE: 31
        FONTTYPE   : 20
        ACTIVE     : 0
        SPRITEID   : -1
        ACCELERATOR: 0
        DRAW TYPE  : 0
        SHARE      : 0
        SOUNDTYPE  : 0
        DESC       :
*
#rem..........Chat List Box Menu
MENUID     : 21
MENUTYPE   : 1
MOVEABLE   : 0
ACTIVE     : 1
SPRITEID   : 764
ACCELERATOR: 0
DRAW TYPE  : 0
SHARE      : -1
X-CORD     : -1
Y-CORD     : -1
DESC       :
[...]
*
~

We start processing these as soon as we see MENUID, I suppose. Each toplevel item is *-delimited, and the list is terminated with ~.

Each menu has a list of parameters:

Name Examples Purpose
MENUID 1, 2, 3 Maybe linking between menus?
MENUTYPE 0, 1, 2, 3, 45, 300 ?
MOVEABLE 0 Unimplemented functionality?
ACTIVE 0, 1, 1,0 ?
SPRITEID -1, 0, 123, 16,-1,1 Select from .obj file?
ACCELERATOR ?
DRAW TYPE ?
SHARE ?
X-CORD -1, 0, 200 X coordinate to draw at
Y-CORD -1, 0, 200 Y coordinate to draw at
FONTTYPE Choose a font from the above?
SOUNDTYPE ?
DESC CHARACTER SELECT, 51005 Text, or reference to Data/USEng.dta

Submenus also show a couple of unique values:

Name Examples Purpose
SUBMENUID 1, 2, 3 As MENUID
SUBMENUTYPE 0, 1, 2 As MENUTYPE

It seems .mnu files can also include other files, which have the extension .mni (presumably for "Menu include"). Examples:

*
$GenDialog.mni
$GenLoad.mni

It looks like we just interpolate the named file into the text when we come across one of these lines.

The MENUID in GenDialog and GenLoad is a 2-element list, like 1000,1 or 2000,2. The second number corresponds to the offset in the list of object files.

MENUTYPE

Here's the full list of values for MENUTYPE:

Value Meaning
0 Background
1 Menu
2 DragMenu
3 RadioMenu ??? - only seen in LevelPly and LoadGame around select-one items
45 MainBackground ??? - only seen in MainGame and MainGameChaos
300 Dialogue

The MENUTYPE acts as a logical grouping of a set of objects onscreen, and gives strong hints about how to handle their children.

SUBMENUTYPE

The types seem to refer to different types of UI widget. Here's a list of unique values:

Value Meaning
3 Button
30 DoorHotspot1
31 DoorHotspot2
40 LineKbd
41 LineBriefing
45 Thumb
50 InvokeButton
60 DoorHotspot3
61 Overlay
70 Hypertext
91 Checkbox
100 EditBox
110 InventorySelect
120 RadioButton
200 DropdownButton
205 ComboBoxItem
220 AnimationSample
221 AnimationHover
228 MainButton
232 Slider
233 StatusBar
400 ListBoxUp
405 ListBoxDown

400, 405, and 45, can all accept 4 values for SUBMENUTYPE in a comma-separated list. These records combine to form a TListBox control, with a number of visible slots that act as a viewport. There is a draggable vertical slider (the "thumb") to show where in the full list the viewport is, and up + down buttons to move the position of the thumb by one, so it's feasible that these values tell us about the available steps.

Here are the values in Briefing.mnu:

#rem..........List Box Menu
MENUTYPE   : 1 # List Box Menu
    SUBMENUTYPE: 400,22,22,13 # Scroll Up
    SUBMENUTYPE: 405,22,22,13 # Scroll Down
    SUBMENUTYPE: 45, 14,15,13  # Thumb

There are 13 elements in this listbox, which sorts out the fourth number (but what is it used for?). The other two need more investigation.

Positioning

The X-CORD and Y-CORD values would seem to be related, to this, but they are universally set to 0 or -1.

Far more important are the XOffset and YOffset values for each sprite in the associated .obj files. Taking these into account is enough to draw Options.mnu successfully, for instance:

However, it's not sufficient to put all the items for MainGame.mnu in the right place.

Animation

This seems to be done by choosing a different sprite to draw every N ticks. They are laid out sequentially, but I don't yet know how to animate them. It's likely to be the same approach as used for other obj files.

Looking at Main.mnu, it points at the object fail Main.obj. This has 118 sprites, which can be described as follows:

Start Count Desc
0 1 Background image
1 3 New game button: base, pressed, disabled
4 3 Load game button: base, pressed, disabled
7 3 Multiplayer button: base, pressed, disabled
10 3 Settings button: base, pressed, disabled
13 3 Quit button: base, pressed, disabled
16 20 New game button: 20 animation frames
36 20 Load game button: 20 animation frames
56 20 Multiplayer button: 20 animation frames
76 20 Settings button: 20 animation frames
96 20 Quit button: 20 animation frames
116 1 Section of background ("Menu title")
117 1 Version hotspot

So we have 5 buttons with very similar characteristics, but at different sprite offsets, and two distinct ranges per button, plus some others. Here's some attributes plucked from Main.mnu:

Name (SUB)MENUTYPE "Active" "SPRITEID" "DRAW TYPE" "SHARE"
Background 1 1 0 0 -1
Start menu 1 1 -1 0 -1
New game 228 1,0 16,-1,1 20 1
Load game 228 1,0 36,-1,4 20 4
MP game 228 1,0 56,-1,7 20 7
Options 228 1,0 76,-1,10 20 10
Quit 228 1,0 96,-1,13 20 13
Menu title 61 1 -1 0 116
V hotspot 61 1 -1 0 117

The buttons, menu title and version hotspot are submenus of the start menu.

ACTIVE

There are only 4 values seen across all menus: 0, 1, 1,0, 102 and 1,1. Perhaps this represents possible states?

Sprite selection

For the background (MENUTYPE: 1), this points simply at the sprite index in the object file. For the start menu, it's -1 (no sprite, I assume). For the menu title and version hotspot (MENUTYPE: 61, it's -1 too.

For the buttons, it's a list pointing to the start of the 20 animated frames, -1, then the start of the 3 static frames.

DRAW TYPE is the number of animated frames. We only use the animated frames when the button is focused. SHARE repeats the start of the static frames, and is the only place they're found for the menu title and version hotspot.