Initial public source release
Split reusable rendering and format support into vectorail-core and vectorail-gc.
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
# game471 test mode
|
||||
|
||||
This note describes the operator/test mode in the arcade `game471.exe`
|
||||
(4.74.00ENG). The structural and layout observations below come from the
|
||||
executable and its shipped resources, not from screenshots.
|
||||
|
||||
## Live entry
|
||||
|
||||
The game exposes twenty logical cabinet inputs through `FUN_00634060`
|
||||
(`0x00634060`). Logical input 0 is the TEST switch.
|
||||
|
||||
During normal operation, the main task at `FUN_006396f0` samples input 0 on
|
||||
every update. Holding it for at least three updates starts the test-mode
|
||||
transition. The game then:
|
||||
|
||||
1. stops the normal game/audio/render tasks;
|
||||
2. waits 45 updates;
|
||||
3. constructs the test-mode text renderer, sprite renderer, input adapter,
|
||||
SE adapter, and BGM adapter;
|
||||
4. initializes the test-mode form system and opens the main form.
|
||||
|
||||
The already generated `game471_bootskip.exe` can reach the original menu under
|
||||
Wine. Once the `GameWare` window is active, press and briefly hold Caps Lock.
|
||||
Caps Lock is the executable's built-in DirectInput fallback for the TEST
|
||||
switch; no test-mode-specific patch is needed.
|
||||
|
||||
The original executable's keyboard fallback table starts at `0x007840f0`:
|
||||
|
||||
| Logical input | Cabinet control | FAST I/O mask | DirectInput fallback |
|
||||
| --- | --- | ---: | --- |
|
||||
| 0 | Test switch | `0x00000040` | `DIK_CAPITAL` (Caps Lock) |
|
||||
| 1 | Service switch | `0x00000001` | `DIK_F1` |
|
||||
| 2 | Coin switch | `0x00000004` | `DIK_F2` |
|
||||
| 3 | Select switch | `0x00000010` | `DIK_F3` |
|
||||
| 4 | Enter switch | `0x00000020` | `DIK_RBRACKET` (`]`) |
|
||||
| 5 | Left booster up | `0x00000100` | `DIK_Q` |
|
||||
| 6 | Left booster down | `0x00000200` | `DIK_A` |
|
||||
| 7 | Left booster left | `0x00000400` | `DIK_LCONTROL` |
|
||||
| 8 | Left booster right | `0x00000800` | `DIK_S` |
|
||||
| 9 | Left booster button | `0x00100000` | `DIK_LMENU` (left Alt) |
|
||||
| 10..14 | Right booster controls | `0x00010000` through `0x00200000` | raw scan codes `78,7d,7a,7b,6a` |
|
||||
|
||||
`FUN_00633d00` obtains the FAST I/O bitfield and masks it with the first table
|
||||
above. `FUN_00633de0` applies the per-input active-high/active-low table.
|
||||
`FUN_00634060` ORs that result with the DirectInput fallback.
|
||||
|
||||
## Test-mode input adapter
|
||||
|
||||
`GWTestModeInput_GW` is constructed by `FUN_00569d00`. Its update method,
|
||||
`FUN_00569d20`, translates cabinet inputs to the generic test-mode flags:
|
||||
|
||||
- Test switch -> `0x20` (back/exit)
|
||||
- Select switch -> `0x02`
|
||||
- Enter switch -> `0x58`
|
||||
- left booster up/down/left/right/button -> `0x01`, `0x02`, `0x84`, `0x48`,
|
||||
`0x10`
|
||||
|
||||
The language table describes the intended behavior:
|
||||
|
||||
- booster up/down or Select moves the cursor;
|
||||
- booster buttons or Enter confirms;
|
||||
- booster left/right or Enter changes a setting;
|
||||
- Test returns/backtracks.
|
||||
|
||||
Short synthetic X11 key taps may be sampled for several game updates because
|
||||
the original runs uncapped. For automated navigation, inject an explicit
|
||||
cabinet state for one update instead of relying on `xdotool key`.
|
||||
|
||||
## Resources
|
||||
|
||||
Test mode does not use the normal RVB/MTX menu assets. Its strings come from:
|
||||
|
||||
- `data/TestModeLaungage/Laungage_eng_sjis.csv`
|
||||
- `data/TestModeLaungage/Laungage_jpn_sjis.csv`
|
||||
|
||||
Both are CP932/Shift-JIS. `Laungage` is the spelling used by the shipped game.
|
||||
The glyphs themselves come from `data/font/Font.mtf` and the
|
||||
`data/font/FontXXXXXXXX.mfi` atlas pages. `GWTestModeRenderText_GW`
|
||||
constructs a pool of 256 regular GameWare text objects backed by that font.
|
||||
It does not use a test-mode-specific bitmap font or GDI text.
|
||||
|
||||
`Font.mtf` starts with a 16-way Unicode radix table. A resolved entry stores
|
||||
the MFI page in its low 24 bits and the high nibble of the atlas cell in bits
|
||||
28..31; the low cell nibble comes from the Unicode codepoint. Each MFI contains
|
||||
a 512x512 DXT5 atlas split into 16x16 cells. This is confirmed by
|
||||
`FUN_00485f90`, which creates GameWare image format 3, and by
|
||||
`GWPCImage2D::Create`, whose format table maps index 3 to `D3DFMT_DXT5`.
|
||||
The font shader uses the DXT5 alpha channel as glyph coverage. The English
|
||||
ASCII glyphs use page 0 and occupy the left half of each cell, producing 8x16
|
||||
glyphs. The selection marker is U+2192 (`→`), resolved by the MTF to page 27,
|
||||
cell `0xb2`, and is 16x16.
|
||||
|
||||
The renderer is a separate, mostly text-based framework represented by the
|
||||
following RTTI classes:
|
||||
|
||||
- `GWTestModeWindowText`, `GWTestModeWindow`, `GWTestModeWindowList`
|
||||
- `GWTestModeForm`, `GWTestModeSelectForm`
|
||||
- `GWTestModeForm_YesNo`, `GWTestModeForm_ProcYesNo`
|
||||
- `GWTestModeInput_GW`
|
||||
- `GWTestModeRenderText_GW`, `GWTestModeRenderSprite_GW`
|
||||
- `GWTestModeBGM_GW`, `GWTestModeSE_GW`
|
||||
|
||||
The framework screen is 720x1280 on black. `FUN_00577940` installs a logical
|
||||
text size of 16x16, pure red `(1,0,0,1)` for the selected/help color, and pure
|
||||
cyan `(0,1,1,1)` for normal selectable entries. The three centered common
|
||||
title windows use normalized y coordinates `-0.95`, `-0.925`, and `-0.9`,
|
||||
which map to pixel y positions 32, 48, and 64.
|
||||
|
||||
The main list is anchored at normalized y `-0.725` (176 px). Its default row
|
||||
gap is `0.01` of the 640-pixel half-height, so rows advance by
|
||||
`16 + 6.4 = 22.4` pixels. The selected row is red and has a separately drawn
|
||||
`→`; unselected rows are cyan. The help form is centered at normalized
|
||||
y `0.2` (768 px), while the main five-line build/machine/time information list
|
||||
is centered at y `0.4` (896 px).
|
||||
|
||||
## Main menu in 4.74.00ENG
|
||||
|
||||
The live build displays:
|
||||
|
||||
1. Monitor Test
|
||||
2. Input/Output Test
|
||||
3. LED Test
|
||||
4. Card Test
|
||||
5. Audio Settings
|
||||
6. Game Settings
|
||||
7. Network Info
|
||||
8. Bookkeeping
|
||||
9. System Info
|
||||
10. Restore factory settings
|
||||
11. Exit Test Mode
|
||||
|
||||
The CSV also contains `Check Input Count`, `System Settings`, `Delete High
|
||||
Scores`, and `Machine Connection Test`, but prefixes those entries with `#`.
|
||||
It contains `Update Online` without `#`, although that item is still filtered
|
||||
out by this build's runtime conditions.
|
||||
|
||||
## Forms and data exposed
|
||||
|
||||
- Monitor Test: color bars, white, red, green, blue, and cross-hatch patterns.
|
||||
- Input/Output Test: all cabinet switches, both five-input boosters, headphone
|
||||
volume/jack state, and Groove Stage connection. Booster buttons drive their
|
||||
lamps; the coin switch changes lockout.
|
||||
- LED Test: all lights and individual title, side, and booster light groups.
|
||||
- Card Test: card-reader status and card ID.
|
||||
- Audio Settings: test BGM, master/headphone/demo levels, five speaker channels,
|
||||
Groove Stage status, and normal/demo vibration intensity.
|
||||
- Game Settings: coin/song price, per-day operating hours, and score-attack
|
||||
mode.
|
||||
- Network Info: location identity/address/IP, cabinet IP/MAC, NESYS versions,
|
||||
and relay server.
|
||||
- Bookkeeping: uptime/play totals, free plays, service-switch count, player
|
||||
statistics, 30-week and hourly histograms, play logs, the last twenty errors,
|
||||
and service-switch history.
|
||||
- System Info: program/system configuration values.
|
||||
- Factory Settings: confirmation form followed by persistent-data reset.
|
||||
|
||||
Persistent test-mode data has separate RTTI classes for system settings, high
|
||||
scores, play/weekly/daily/error/service-switch logs, and game-unique data. Log
|
||||
paths embedded in the executable live under `TestModeFile\...\Log`.
|
||||
|
||||
### Coin/song presets
|
||||
|
||||
`CTestModeForm_GameSetting` chooses its coin/song table from the Type X
|
||||
`HKLM\SOFTWARE\taito\typex\Country` registry value. `Country == 0` uses eight
|
||||
entries, in this exact order:
|
||||
|
||||
1. 1 coin, 2 songs
|
||||
2. 1 coin, 3 songs
|
||||
3. 2 coins, 2 songs
|
||||
4. 2 coins, 3 songs
|
||||
5. Free play, 1 song
|
||||
6. Free play, 2 songs
|
||||
7. Free play, 3 songs
|
||||
8. 1 coin, 1 song
|
||||
|
||||
For a non-zero country value it instead exposes 39 entries: every combination
|
||||
of 1 through 12 coins with 1 through 3 songs, followed by the three free-play
|
||||
variants. `FUN_00570a70` and `FUN_00570810` wrap the selected index forward and
|
||||
backward respectively.
|
||||
|
||||
OpenRoller mirrors the registry value with `Country` in `openroller.cfg` beside
|
||||
the executable. CMake creates the file on the first build but leaves an
|
||||
existing copy untouched. The value is reread whenever test mode is entered, so
|
||||
the application does not need to be rebuilt after changing it.
|
||||
|
||||
## Useful code addresses
|
||||
|
||||
| Address | Role |
|
||||
| ---: | --- |
|
||||
| `0x006396f0` | top-level boot/game/test-mode state machine |
|
||||
| `0x00634060` | logical cabinet input + DirectInput fallback |
|
||||
| `0x00633d00` | mask current FAST I/O input bitfield |
|
||||
| `0x00633de0` | apply active-level table |
|
||||
| `0x00569d00` | construct `GWTestModeInput_GW` |
|
||||
| `0x00569d20` | translate game inputs to generic test-mode input flags |
|
||||
| `0x00569610` | construct `GWTestModeRenderText_GW` |
|
||||
| `0x00569ad0` | construct `GWTestModeRenderSprite_GW` |
|
||||
| `0x00569440` | construct `GWTestModeSE_GW` |
|
||||
| `0x005693f0` | construct `GWTestModeBGM_GW` |
|
||||
| `0x00577940` | initialize test-mode form/render state |
|
||||
| `0x00634fd0` | credit/service-credit handling and `SERVICE-SW LOCKED` |
|
||||
|
||||
`SERVICE-SW LOCKED` is unrelated to entering test mode. It is emitted by the
|
||||
credit controller after repeated Service-switch credit pulses and holds the
|
||||
service-credit lock for 180 updates.
|
||||
|
||||
## LED output pipeline
|
||||
|
||||
The LED test form's main methods are:
|
||||
|
||||
| Address | Role |
|
||||
| ---: | --- |
|
||||
| `0x0056e160` | construct `CTestModeForm_LEDTest` |
|
||||
| `0x0056e390` | update the selected LED test pattern |
|
||||
| `0x0056e6c0` | handle the seven LED-test menu items |
|
||||
| `0x0062b0e0` | set logical LED `index` to `R,G,B,alpha` |
|
||||
| `0x0062d4d0` | construct all logical LED objects and their hardware mapping |
|
||||
| `0x0062a4d0` | update one `CLedDevice` and place its value in the cabinet output buffers |
|
||||
| `0x004b3b40` | write one RGB pixel into the shared board buffer |
|
||||
| `0x004b4c50` | pack shared LED buffers into the FIO transfer blocks |
|
||||
| `0x004b55f0` | exchange registers and transfer blocks with `iDmacDrv32` |
|
||||
| `0x004b6700` | wrapper for `iDmacDrvRegisterBufferWrite` |
|
||||
|
||||
### Logical groups
|
||||
|
||||
There are 118 logical LED objects:
|
||||
|
||||
| Logical indices | Test-mode group | Hardware coordinates |
|
||||
| ---: | --- | --- |
|
||||
| `0` | left booster button | simple output 4 |
|
||||
| `1..8` | left booster RGB group 8 | board 0, group 8, positions 0..7 |
|
||||
| `9..40` | left booster RGB groups 0..7 | board 0, groups 0..7, positions 0..3 |
|
||||
| `41` | right booster button | simple output 5 |
|
||||
| `42..49` | right booster RGB group 8 | board 1, group 8, positions 0..7 |
|
||||
| `50..81` | right booster RGB groups 0..7 | board 1, groups 0..7, positions 0..3 |
|
||||
| `82..93` | title | board 2, strips 0..1, pixels 0..5 |
|
||||
| `94..105` | left side | board 2, strips 2..3, pixels 0..5 |
|
||||
| `106..117` | right side | board 2, strips 4..5, pixels 0..5 |
|
||||
|
||||
The menu implements the groups directly:
|
||||
|
||||
- item 0 cycles all 118 LEDs through off, white, red, green, and blue;
|
||||
- items 1, 2, and 3 fill the twelve title/left/right-side LEDs white one
|
||||
address at a time, then clear them in the same order;
|
||||
- items 4 and 5 perform the same fill/clear sequence across 41 LEDs on the
|
||||
corresponding booster;
|
||||
- item 6 starts the form-exit sequence.
|
||||
|
||||
The LED screen itself is only the generic seven-row `GWTestModeWindowList`,
|
||||
anchored at y `-0.725` with an explicit row gap of `0.05` (48 px row
|
||||
advance). It does not draw a schematic of the cabinet or booster rings.
|
||||
|
||||
The all-light loop special-cases logical LEDs 0 and 41 because the booster
|
||||
button lamps are single-channel. For those two, it ORs `R|G|B` and writes the
|
||||
same intensity as a simple lamp.
|
||||
|
||||
The executable establishes 40 independently controlled RGB positions plus one
|
||||
simple button lamp per booster. The `group/position` coordinates above describe
|
||||
the software/FIO mapping only; they do not establish the physical arrangement
|
||||
of those RGB positions inside the arcade booster's plastic assembly.
|
||||
|
||||
### Color representation
|
||||
|
||||
`FUN_004b3b40(board, strip, pixel, R, G, B)` stores each full-color LED as
|
||||
three bytes in this order:
|
||||
|
||||
```text
|
||||
B, R, G
|
||||
```
|
||||
|
||||
Each board reserves `9 * 8 * 3 = 0xd8` bytes even where fewer than eight
|
||||
pixels are connected. Before placing a value in the hardware buffer,
|
||||
`CLedDevice` applies the executable's integer gamma curve independently to
|
||||
each channel:
|
||||
|
||||
```text
|
||||
wire_channel = min(channel * channel / 255, 255)
|
||||
```
|
||||
|
||||
The alpha/intensity field is applied by the LED object before this final
|
||||
conversion. Test mode always passes alpha `0xff`.
|
||||
|
||||
### iDmac/FIO transfers for board type 0x825c
|
||||
|
||||
The current shim reports FIO type `0x825c`; the game selects its `0x25c`
|
||||
packing branch. Each hardware update eventually makes these calls:
|
||||
|
||||
| Register-buffer address | Bytes | LED content |
|
||||
| ---: | ---: | --- |
|
||||
| `0x5000` | `0x1b0` | general FIO block; title bytes at offset `0x168`, button lamps at offsets 4 and 5 |
|
||||
| `0x5200` | `0x1e0` | general FIO block; left/right-side bytes at offset `0x168` |
|
||||
| `0x5400` | `0x0d8` | raw board-0 buffer: left booster |
|
||||
| `0x5600` | `0x0d8` | raw board-1 buffer: right booster |
|
||||
|
||||
The board-2 source buffer is split as follows:
|
||||
|
||||
- its first `0x30` bytes (two 8-pixel strip slots) go to
|
||||
`0x5000 + 0x168`;
|
||||
- its following `0x60` bytes (four 8-pixel strip slots) go to
|
||||
`0x5200 + 0x168`.
|
||||
|
||||
The unused bytes in those strip slots remain zero. This was confirmed both in
|
||||
the decompiled `GWInputDeviceXioFio_BOOST` update path and in the live
|
||||
`idmac_shim.log`: normal steady-state writes have sizes `1b0`, `1e0`, `d8`,
|
||||
and `d8` respectively. Initial device negotiation first sends four `0x200`
|
||||
byte blocks, then switches to the exact steady-state lengths above.
|
||||
|
||||
The game also contains a `0x23c` packing branch and generic transfer banks
|
||||
through `0x5e00`, but those are not selected by the current emulated hardware
|
||||
ID.
|
||||
Reference in New Issue
Block a user