Three things it is not

  • Not a card battle. The four “cards” are the four direction commands, always the same four, each at that fighter’s own AP cost. Nothing is drawn, discarded or reshuffled.
  • Not turn-limited. A leg ends on a knockout and on nothing else. The “Turns Left” strip in the same overlay belongs to a timed boss fight.
  • Not part of the minigame-hub family. It shares no controller library with fishing, the slot machine, dance or Baka Fighter.

At a glance

Contest init / re-entry
FUN_801CEA6C, PROT 0977 at base 0x801CE818
Contest hub
FUN_801CF870, state byte DAT_801D1A78, 51-entry jump table 0x801CE990 (fourteen real states)
Opponent installer
FUN_801D1510
Tally screen / row maths
FUN_801CF074 / FUN_801D1184
Settlement
FUN_801D0F60
Leg
The shared battle round driver FUN_801D0748 and action SM FUN_801E295C, PROT 0898
Contest cursor
_DAT_8007BAC0: low byte packs (course, round); bits 0x100 / 0x200 restrict items / Ra-Seru
Coins
Running tally _DAT_80084440, coin bank 0x800845A4
Tables
Roster 0x801D1920, course descriptors 0x801D1A08, score table 0x801D1860
Port
engine-minigames::muscle_dome, muscle_ringside; engine-battle-menus::muscle_dome_session; engine-minigame-scenes::muscle_dome_scene

Getting there

The door is the mode-24 minigame warp: field-VM op 0x3E with op0 = 105 (sub-id 5) sets game mode 0x18 and loads the overlay. It is the ordinary scene-backup, overlay-load, return-to-field sequence, so the game returns to the exact field state it suspended. The mechanism is on the field / event VM page.

Every dome door on the disc is in one casino record - the course menu. Each arm debits its entry fee and latches a course flag before its own warp. The battle exit selector is the second of only two writers of game mode 24: with the contest bit set it stores the arena mode instead of the field’s, which is what returns a finished round to the arena.

The contest hub

fresh contest 0..2 Welcome strip in, hold, out 3 Title zoom scale 0x1640 to 0x1000 4..5 Course card hold 0xB4, skippable 6 Wall drain kicks the battle load leg survived, course continues 0x0A INTERVAL heading fades in 0x0B Tally roll pad latches fast roll 0x0C HP restore the three healing lanes 0x14 Backdrop return 0x15 ROUND card hold 0x3D, skippable 0x16 Card fade-out starts the fight The leg: an ordinary battle round driver FUN_801D0748, PROT 0898 Arena re-entry FUN_801CEA6C reads "survived" and the course length knockout 0x32 Settle pay out, leave the arena lost, ran, or course exhausted
Two state machines are stacked. The inner one is the battle, with exactly one contest-gated arm (the flee). The outer one is the contest, entirely in PROT 0977, re-entered after every leg. No turn boundary reaches the hub: the intermission is per fight, not per turn.

What a leg’s end routes to

LegNext hub state
survived, course not exhausted0x0A - the between-leg tally
survived, course exhausted0x32 - settle, continuing
not survived0x32 - settle
ran0x32 - settle, gave up

“Survived” is a single bit test on re-entry. “Continuing” is derived, not prompted - there is no continue prompt; the latch is raised on the one path where the course is exhausted and the fighter survived.

The tally heals

RowValueDrains into
roundround * 2 * max_hp / 100the HP accumulator
turnsmin(turns_taken, 8) * max_hp / 100the HP accumulator
outcome[8, 12, 4, 2][min(outcome, 3)] * max_hp / 100the HP accumulator
scorescore_table[course][round - 1]the coin tally

Three of the four lanes are healing, not score; only the fourth is coins. So a contest costs no permanent HP. The lanes drain one after another, one scaled step per frame with a voice blip per step.

The roll can be fast-forwarded. The tally arm opens by testing the press mask against 0xF4 and latching DAT_801D1AB4 (0x801CFD60..0x801CFD7C). That word is the step scaler’s bypass: while it is up a lane moves its whole remainder in one step, so one press rolls out everything left. Its only clear is the arena init.

Hub screens are envelopes

Each hub screen is a fade-in at its own rate, a hold and a fade-out. The counters are brightness levels clamped at 0x80 - a textured primitive’s neutral modulation - not durations, and every step is scaled by the adaptive frame-skip factor. The two card holds end early on any bit of pad & 0xF4. A port that counts frames ends the screens at the wrong instants and cannot be ended early by a button; one that draws them at 0x100 is twice retail’s brightness.

Settlement

CaseEffect
Continuingkeeps the tally and adds the final score cell
Not continuinghalves the tally
Gave upzeroes the tally
Gave up on round 1also sets a per-course flag - the trigger for running from the first battle in all three difficulties
Master course final fight, first timeawards the War God Icon, once per save

A leg plays out as a battle

Nothing about a leg’s choreography is the dome’s own: a turn acts out on the battle’s animation and locomotion code, and the port plays it on the same kernels its battles use.

PieceWhat decides it
Clip speedthe anim tick’s rate law: rate / 4 keyframes a vsync at the normal speed byte
Where the walk stopsthe range law FUN_8004E2F0: the attacker’s live position against the target’s body pair, the monster’s size class and the party reach offset
Traveleach clip’s own root speed and end step; a reaction slides its body back
The hitthe swing’s event frame; a flinch, or a knockdown on the killing hit
Walking homenone - the next string starts where the last one left the pair

A walk that stopped on a margin of its own rather than on the range law is what left daylight between a fist and its target.

See also

The cursor packing, the course ladder, both restores, the arena data file and ringside stills, the round driver’s phases, the command input and the sound are in docs/subsystems/minigame-muscle-dome.md.