Lapis and Mystic Shield Cort
Three boss oversights, explained from the game's own code on the USA disc: why the super-boss Lapis stops casting Lapis Wave once the party has left and come back, why that fight can be fled at all, and why Mushura and Theeder land extra hits on Cort while his Mystic Shield is up - and why only Mushura's add up to extra damage.
SCUS_942.54 runtime addresses.
Shared vocabulary
Each fighter in a battle has an actor record. Pointers to them sit in a table at 0x801C9370: party in slots 0-2, enemies in slots 3-6, a summoned creature in slot 7. The battle's shared state is the context at *0x8007BD24. The battle logic is PROT entry 0898 (loaded at 0x801CE818); each spell and summon is its own small module, PROT entries 0903-0966, all loaded at 0x801F69D8 (see battle and battle action).
| Actor offset | Field |
|---|---|
+0x14C / +0x14E | HP, current / maximum |
+0x150 / +0x152 | MP, current / maximum |
+0x1D9 / +0x1DA | Animation clip now playing / clip staged to play next |
+0x1DE / +0x1DF | Chosen action category / action id |
+0x1EF..+0x1F2 | Reaction clips: flinch, alternate flinch, knockdown, get-up |
How the captures were made
No save in front of Lapis or Cort was available, so the fights were built from a nearby one. Each measurement on this page has this pedigree:
- Forced formation. Every fight starts from a retail save state at the Queen Bee fight in Rim Elm - a scripted battle about to begin, with Vahn alone. At the instruction that reads the first byte of that battle's formation row (
0x801DA600) the row is overwritten in memory:01 00 00 01 B4for Cort, and00 00 00 01 A7 00 00 00for Lapis, the exact bytes of the disc's own row. Everything after that read is the game's code on the game's data: the flag, the monster load, the stat boost, the boss's turn logic, Cort casting and losing his own Mystic Shield. What is not the real fight: the party (Vahn alone, at opening-chapter stats), the stage (Rim Elm) and the frame load, which is lighter than with three characters on screen. - Injected casts. Vahn owns none of these spells. When his turn is set up, his queued action is rewritten to the spell; the game then loads and runs the spell's module itself.
- Poked values. Vahn's HP is held at 9000 so he survives, and his MP is topped up. For the summon measurements his magic level for the spell is set to 1 - at the default the damage roll saturates at 9999 and hides the shield's halving. For the "no shield" baseline Cort's HP is written to 25000 and the game breaks the shield itself on the next frame. For the Lapis MP check, Vahn's current MP is written to 0 once. "Captured on a poked state" below means one of these.
- Which runs are cited. A first batch of these runs held Vahn's HP with a write that began before the battle existed, and so also wrote field memory for the first few seconds. Every experiment was rerun with that write confined to the battle. The reruns gave the same counts, and they are the ones cited; the single exception is marked where it is used.
Lapis Wave checks current MP
- Reported as
- Lapis Wave tests the party's current MP where it was meant to test maximum MP, so Lapis can be killed outright with magic the party is not supposed to have (community report)
- Cause
- Lapis decides whether to cast by counting party members with current MP above zero; leaving a battle saves current MP only, so a returning party reads 0 of its full maximum and is never targeted again
- Where
- Lapis's turn logic at
0x801EBC38in PROT entry 0898; the wave itself at0x801F6A04in PROT entry 0943 - Affects
- The Lapis fight only
- Status
- explained - from disassembly and disc data; the wave, the check and the Jedo kill each captured in a forced fight, the flee-and-return route not played through
Lapis Wave is not a damage attack. It sets both the current and the maximum MP of every party member to zero for the rest of that battle. That is why MP items do nothing afterwards: there is no maximum left to fill. In the captured fight Lapis casts it before the party can enter a command, and Vahn's MP goes from 27 / 27 to 0 / 0.
The check the report describes is in Lapis's turn logic, not in the attack. Each time Lapis acts it counts the party members whose current MP is above zero and casts the wave only if it finds one. A party at zero current MP is left alone, whatever its maximum is: with Vahn's current MP written to 0 and his maximum left at 27, Lapis attacked physically on both of its turns and never cast the wave (captured on a poked state).
Leaving a battle writes each member's current MP back to their permanent record and never writes the maximum. So a party that takes one wave and flees walks away at 0 MP with its real maximum untouched. On the return visit Lapis sees nobody with MP and never casts the wave; an MP item works again; and a caster who gets a turn before Lapis's next one can cast.
The spell that ends the fight is Jedo. Its module has two outcomes: against a fight flagged as scripted it deals normal rolled damage, against an unflagged one it sets every living enemy's HP to zero with no roll. The Lapis fight is unflagged (next section), so the kill is certain: an injected Jedo took Lapis from 64800 HP to 0 in a single write. A check on maximum MP would have fired on the returning party and closed the route; whether the designers meant that field is an inference, not something the code states.
These pieces were captured one at a time. The wave, the check at zero MP and the Jedo kill are each observed; the flee, the return visit and the MP item between them are read from the code and have not been played through as one route.
- Forced ambushBattle setup compares the first enemy id with
0xA7(Lapis) and forces a back attack, so Lapis acts before the party can enter a command. Captured: the first action of the fight is Lapis's.0x80051FC4 - The checkLapis's turn counts party actors with
+0x150(current MP) non-zero. None: an ordinary attack. One or more, and Lapis holds 255 MP: Lapis Wave.0x801EBC68 - The waveFor every party seat: current MP and maximum MP both written to zero. Captured: 27 / 27 to 0 / 0, and the cast costs Lapis 255 of its 4000 MP.
0x801F6D08,0x801F6D1C - The exitFleeing copies current MP to the character record. Maximum MP is not copied.
0x801E7C78 - The returnThe battle reloads MP from the record: 0 current, full maximum. The check finds nobody and never fires.
- The killJedo on an unflagged fight sets each living enemy's HP to 0. Captured: 64800 to 0.
0x801F8814
Register-level walkthrough
Ambush, FUN_80051D84 in SCUS_942.54:
80051fc0 lbu v1,-0x42f4(v1) ; first formation id, 0x8007BD0C
80051fc4 li v0,0xa7
80051fc8 bne v1,v0,0x80052068
80051fd0 li v0,0x1
80051fe0 sb v0,0x290(v1) ; ctx[+0x290] = 1, back attack
The check, FUN_801E9FD4 in PROT entry 0898. The routine switches on the enemy id through a jump table at 0x801CF1CC (index id - 4); the entry at 0x801CF458 sends Lapis to 0x801EBC38:
801ebc60 lw v0,0x0(v1) ; party actor i
801ebc68 lhu v0,0x150(v0) ; current MP
801ebc70 beq v0,zero,<next>
801ebc78 addiu s1,s1,0x1 ; count members with MP
801ebc90 beq v0,zero,0x801ebdac ; nobody: generic pick
801ebc98 lhu v0,0x150(s4) ; Lapis's own MP
801ebca0 sltiu v0,v0,0xff
801ebca4 bne v0,zero,0x801ebdac ; needs 255
801ebcac sb v0,0x1de(s4) ; category 2, magic
801ebcb4 li v0,0xb5 ; Lapis Wave -> +0x1DF
The wave, FUN_801F6A04 in PROT entry 0943, third arm, once per party seat. The module calls no damage routine anywhere:
801f6cf4 lhu v0,0x150(v1)
801f6cfc sh v0,0x178(v1) ; MP readout drains from the old value
801f6d08 sh zero,0x150(v0) ; current MP = 0
801f6d1c sh zero,0x152(v1) ; maximum MP = 0
The exit, FUN_801E791C in PROT entry 0898: actor +0x150 is stored to the character record's current MP (+0x10A) at 0x801E7C78..0x801E7C80. The routine has no store of +0x152.
Jedo, FUN_801F6A58 in PROT entry 0931:
801f87d4 lbu v0,0x287(v1) ; scripted-fight flag
801f87dc bne v0,zero,0x801f8844
801f8804 lhu v0,0x14c(a0) ; each enemy seat 3..6
801f8814 sh zero,0x14c(a0) ; HP = 0
801f8820 sb a2,0x21c(v0) ; defeat fade
Nighto (PROT entry 0907) also reaches its kill on this fight, as a roll: the resist test is skipped when the flag is clear (0x801F6BF0), the resist roll is rand % (0x13 - magic_level) < 9 (0x801F6C28), and the kill is rand % 8 == 0 (0x801F6B50, store at 0x801F7E58). At magic level 9 that is about 11% per cast.
Addresses
| Address | Image | What | Evidence |
|---|---|---|---|
0x80051FC0..0x80051FE0 | SCUS_942.54, FUN_80051D84 | Enemy id 0xA7 forces the back attack, ctx[+0x290] = 1 | disassembly, capture |
0x801CF1CC, word at 0x801CF458 | PROT 0898 | Turn-logic jump table; Lapis's arm is 0x801EBC38 | disc data |
0x801EBC38..0x801EBCB4 | PROT 0898, FUN_801E9FD4 | Count party +0x150, require own MP of 255, queue action 0xB5 | disassembly, capture |
0x801F6A04 | PROT 0943 | Lapis Wave body | disassembly |
0x801F6CFC, 0x801F6D08, 0x801F6D1C | PROT 0943 | Stores to +0x178, +0x150, +0x152 for each party seat | disassembly, capture |
0x801E7C78..0x801E7C80 | PROT 0898, FUN_801E791C | Flee: current MP saved to record +0x10A | disassembly |
0x80084708 + n * 0x414 | RAM | Character record; +0x108 maximum MP, +0x10A current MP | repo doc |
0x801F87D4..0x801F8820 | PROT 0931, FUN_801F6A58 | Jedo, flag clear: every living enemy's HP set to 0 | disassembly, capture |
0x801F833C, 0x801F8438 | PROT 0931 | Jedo, flag set: rolled damage instead | disassembly |
0x801F6BF0, 0x801F6C28, 0x801F6B50, 0x801F7E58 | PROT 0907, FUN_801F69E8 | Nighto: resist gate, resist roll, kill roll, kill store | disassembly |
Spell record 0xB5 | SCUS_942.54 spell table | Lapis Wave: cost 255, targets the whole party | disc data |
Monster record 167, +0x20 | PROT 0867 | Lapis's resist byte is 1 | disc data |
Scope
- The code does not require the escape. Any party that walks in with every member at zero current MP is never waved. Captured on a poked state: with Vahn's current MP written to 0 before Lapis's first pick and the maximum left at 27, Lapis opened with a physical attack, attacked physically again on its next turn and kept all 4000 MP. Those two turns are all the capture covers. The reported route is flee and return, which works because the wave itself produces the zero.
- One member holding a single point of MP re-arms the wave for everyone. The count has no "is this member alive" test, so a fallen member's MP counts.
- Lapis needs 255 MP of its own for each cast.
- That MP items do nothing at zero maximum is a community report consistent with the code; the item routine's cap was not re-read for this page.
Verifying it
Observed in the forced Lapis fight (forced formation, Vahn alone with 27 MP; see how the captures were made):
- Lapis acts first, with no command prompt before it, and the action is Lapis Wave: the cast loads PROT entry 0943 and costs Lapis 255 MP.
- Vahn's
+0x150and+0x152both go from 27 to 0 during the wave. On its next turn, with the party at 0 / 0, Lapis attacks physically. - With
+0x150written to 0 and+0x152left at 27, no wave is cast. The maximum being non-zero when the check runs is what tells the two fields apart. - Jedo, injected:
ctx[+0x287]reads 0 at0x801F87DC, the write at0x801F8814zeroes Lapis's 64800 HP, and the damage roll at0x801F8438never runs.
The run that shows the wave also carries two unrelated one-byte writes to Vahn's character record (a summon level stash and his Ra-Seru item byte), made for a different question.
Still to check in a played game:
- After a real escape, read the character record:
+0x108unchanged,+0x10Azero. - On the return visit, break at
0x801EBC68:+0x150reads 0,+0x152the real maximum, and the branch at0x801EBC90is taken.
Open questions
- Whether the check was meant to read maximum MP. The code is equally consistent with a check written for the in-battle case, where both fields are zero after a wave.
- Whether the restored caster reliably acts before Lapis (speed 451) was not simulated.
- The route as a whole (wave, flee, return, MP item, Jedo) has not been played through in one capture; the flee's save of current MP and the MP item rest on the code alone.
Lapis can be escaped from
- Reported as
- The party can run from Lapis, unlike other bosses (community report)
- Cause
- "No escape" is one byte at the start of the fight's formation row, and Lapis's row has it at zero
- Where
- Mt. Dhini scene data (PROT entry 0383), formation row 11; read by the escape roll at
0x801E7B14 - Affects
- Lapis, plus the Rim Elm opening fights and Gold Face at the Shadow Gate
- Status
- explained - from disassembly and disc data; the clear flag and Lapis's stats captured in a forced fight, the Run command itself not driven
Each scene carries a table of enemy formations, eight bytes a row. The first byte of a row says "this is a scripted fight". When it is non-zero the game sets a flag for the battle, and the escape roll fails whenever that flag is set. Nothing else makes a fight inescapable: not the script command that starts it, and nothing in the monster's own data.
Lapis's row has zero there. The fight is started by a script command exactly like a boss fight, yet the battle treats it as an ordinary encounter, so Run, the escape accessories and the Spikefish Flute all work. A fight started from that row's exact bytes reads the flag as zero from start to finish; choosing Run was not part of that capture.
Lapis: Mt. Dhini (deene), row 11, at offset 0x38C3 of the decoded scene data.
For comparison, Cort: scene chitei2, row 13. The only difference that matters is the first byte.
The same flag feeds every other boss protection in the battle code, so the Lapis fight loses those as well. This is what lets the instant-kill summons of the previous section land.
| What reads the flag | Effect on the Lapis fight | Evidence |
|---|---|---|
Escape roll, 0x801E7B14 | The party can flee | disassembly |
Jedo's kill arm, 0x801F87D4 | Certain kill | disassembly, capture |
Nighto's resist gate, 0x801F6BF0 | Kill and confuse rolls run although Lapis's record has the resist byte set | disassembly |
| Zenoir's and Aluru's resist gates | Same gate as Nighto | repo doc |
Seru-magic stat debuffs, FUN_801F3D3C | Land on every hit, with no suppression roll | repo doc |
Enemy stat boost at battle load, FUN_80054CB0 | The random-encounter profile is installed instead of the boss one | disassembly, capture |
| Spikefish Flute, PROT 0925 | Its flee outcome runs | repo doc |
The stat-boost row means Lapis is weaker in attack and defence, and stronger in magic, than stat lists say:
| ATK | Upper defence | Lower defence | INT | |
|---|---|---|---|---|
| Lapis's record on the disc | 680 | 975 | 987 | 999 |
| Installed in the Lapis fight (flag clear) | 680 | 1705 | 1726 | 1248 |
| What a flagged boss fight would install | 850 | 1950 | 1974 | 1123 |
The middle row is read from Lapis's actor in the forced fight, along with HP 64800 and MP 4000. The same rule shows on unmodified save states of another unflagged scripted fight, Tetsu's opening spar: the flag reads 0 and his record's 24 / 16 / 12 / 99 is installed as 24 / 28 / 21 / 123, while flagged Gaza and evolved Cort states read 4 and carry the boss boost (see battle formulas for the two profiles).
Published stat lists, this project's own curated bestiary included, show 850 / 1950 / 1974 / 1123 for Lapis. That is the boss boost applied uniformly to every enemy - a derived column, not a reading of this fight.
Register-level walkthrough
Where the flag comes from, FUN_801DA51C in PROT entry 0897, at battle launch:
801da5f8 lw v0,0x94(s1) ; the formation row
801da600 lbu v0,0x0(v0) ; its first byte
801da608 beq v0,zero,0x801da620
801da610 lbu v0,-0x42a0(v1) ; per-battle flags, 0x8007BD60
801da618 ori v0,v0,0x80
801da61c sb v0,-0x42a0(v1)
The latch, FUN_800513F0 in SCUS_942.54, 0x80051430..0x80051444: ctx[+0x287] = (flags >> 5) & 4, stored before any monster is loaded. The same routine then clears bit 0x80 of 0x8007BD60 again (0x80051A14), so during a fight only ctx[+0x287] tells a flagged fight from an unflagged one.
The escape roll, FUN_801E791C in PROT entry 0898:
801e7afc sltu v0,s2,s3 ; party roll < enemy roll
801e7b00 bne v0,zero,0x801e7b24 ; fail
801e7b14 lbu v0,0x287(v0)
801e7b1c beq v0,zero,0x801e7b40 ; flag clear: success path
The script command: in the Mt. Dhini scene data the fight starts with 3E FF 0B at offset 0x3840 - "scripted battle, formation row 11". The command itself writes no flag (see encounter records).
The stat boost, FUN_80054CB0 in SCUS_942.54 (s4 is the monster record):
80055234 lbu v0,0x287(v0)
8005523c beq v0,zero,0x800552ac ; flag clear: second block
80055248 lhu v0,0x12(s4) ; flagged: ATK += ATK >> 2
80055264 lhu v1,0x14(s4) ; UDF += UDF
80055280 lhu v1,0x16(s4) ; LDF += LDF
8005529c lhu v0,0x18(s4) ; INT += INT >> 3
800552ac lhu v1,0x14(s4) ; clear: UDF += (UDF >> 1) + (UDF >> 2)
800552d0 lhu v1,0x16(s4) ; LDF += (LDF >> 1) + (LDF >> 2)
800552f8 lhu v0,0x18(s4) ; INT += INT >> 2
The clear block leaves ATK alone. Its two shifts round down separately, so 975 becomes 975 + 487 + 243 = 1705, one less than a straight "times 7/4" would give.
Addresses
| Address | Image | What | Evidence |
|---|---|---|---|
0x801DA5F8..0x801DA61C | PROT 0897, FUN_801DA51C | Row byte 0 non-zero raises bit 0x80 of 0x8007BD60 | disassembly |
0x80051430..0x80051444 | SCUS_942.54, FUN_800513F0 | ctx[+0x287] = (flags >> 5) & 4 | disassembly, capture |
0x80051A14 | SCUS_942.54, FUN_800513F0 | Bit 0x80 of 0x8007BD60 cleared again after the latch | disassembly |
0x80055234..0x80055308 | SCUS_942.54, FUN_80054CB0 | Stat boost: boss block, or the clear block at 0x800552AC | disassembly, capture |
0x801E7AFC..0x801E7B24 | PROT 0898, FUN_801E791C | Escape roll: flag set forces the failure arm | disassembly |
Scene data offset 0x3840 | PROT 0383 (deene) | 3E FF 0B: scripted battle on formation row 11 | disc data |
Scene data offset 0x38C3 | PROT 0383 (deene) | Row 11: 00 00 00 01 A7 00 00 00 | disc data |
| Monster record 167 | PROT 0867 | Lapis before the boost: ATK 680, upper defence 975, lower defence 987, INT 999 | disc data |
Scope: every scripted fight with the byte at zero
Joining every scripted-battle command on the disc to the formation row it names gives this complete list:
| Scene | Command | Row | Enemies |
|---|---|---|---|
deene (Mt. Dhini) | 3E FF 0B | 11 | Lapis |
town01 (Rim Elm) | 3E FF 04 | 4 | Tetsu, the opening spar |
town0b, town0c (Rim Elm) | 3E FF 03 | 3 | Queen Bee and three Killer Bees |
town0b (Rim Elm) | 3E 00 02 | 2 | One Gimard |
stone (Shadow Gate) | 3E 00 03 | 3 | Gold Face |
Every other scripted fight names a flagged row: the Piura pair, Zeto, every Songi, the Viguro pair, every Caruban, Dohati, every Berserker, the Kemaro pair, Van Saryu, Xain, the late Tetsu, both Gaza fights, the three Delilas siblings, Koru, Rogue, Jette and both Cort forms. Lapis is the only late-game boss on the unflagged side.
Verifying it
Observed in a fight forced from the disc row's bytes (see how the captures were made):
ctx[+0x287]reads 0 for the whole fight; a flagged boss reads 4. The flags byte0x8007BD60is no use for this check: its bit0x80is cleared during setup in every fight.- Lapis's actor at
*(0x801C9370 + 0xC)reads 680 / 1705 / 1726 / 1248 at+0x158/+0x15C/+0x160/+0x168.
Still to check: choose Run in the Lapis fight and break at 0x801E7B14. The prediction is ctx[+0x287] = 0 and, on a winning roll, the success path at 0x801E7B40.
Open questions
- The escape itself was not driven in a capture; that it succeeds rests on the code of the roll and on the flag reading 0.
- The fight was started by forcing the formation row, not by reaching Lapis on Mt. Dhini. Everything that depends on the row and on Lapis's own data is the real game; the party and the stage are not.
Mushura and Theeder against Mystic Shield
- Reported as
- Mushura and Theeder do excessive damage to Cort while his Mystic Shield is up; Crazy Driver racks up hits on the shield, the only place in the game where that happens (community report)
- Cause
- Both summons rely on the target's flinch animation to stop repeat hits, and Mystic Shield removes Cort's flinch. Mushura then hits on every tick it touches him; Theeder hits twice, which only cancels the shield's halving
- Where
- Hit tests at
0x801F7870(Mushura, PROT entry 0915) and0x801F7CF0(Theeder, PROT entry 0904); shield setup at0x801F7690(PROT entry 0940) - Affects
- Cort's first form for his first 25000 HP
- Status
- explained - mechanism from disassembly; hit counts and damage measured in a forced Cort fight with injected casts
The two summons turn out to be different cases. Mushura's Crazy Driver really does deal excess damage to shielded Cort: measured, 28 run-over hits where an unshielded cast lands 4, and 2252 damage against 784 - about 2.9 times an unshielded cast. Theeder only slips past the shield: its beam lands 2 hits where an unshielded cast lands 1, each at half strength, for 284 damage against 282. The shield is cancelled out, not exceeded.
Element, overflow and a special formula play no part. Every summon uses the same damage roll, and the shield halves every hit on Cort - these two included.
The difference is how these two decide when to hit. Most summons hit on a fixed beat of their animation. Mushura and Theeder are sweeps: on every tick they test each enemy for contact with the rolling body or the swinging beam, and hit whatever is touching. The one thing that stops them from hitting the same enemy again is a test that the enemy is standing idle. A hit makes the enemy flinch or fall, and an enemy in the middle of that reaction is skipped.
Mystic Shield wipes Cort's four reaction animations so that he stands unmoved behind it. Animation number zero is the idle stance. So a hit now tells Cort to play "idle", he is still idle at the next contact, and the sweep hits him again. Mushura rolls back and forth across him and stays in contact for many ticks. Theeder's beam crosses him exactly twice.
Mule, a Ra-Seru summon built the same way, has an extra line at the same spot: if Mystic Shield is up, skip the hit. Mushura and Theeder lack it. Three summons share the pattern and one of them is guarded.
| Cast | Cort's state | Hits | Roll per hit | HP lost |
|---|---|---|---|---|
| Theeder | shield broken by the game at 25000 HP | 1 | 282 | 282 |
| Theeder | shield up | 2 | 142, 142 | 284 |
| Theeder | shield up, reaction clips written back to 03 02 04 05 | 1 | 141 | 141 |
| Mushura | shield broken by the game at 25000 HP | 4 run-over + 1 opening | 610 to 639, then quartered | 784 |
| Mushura | shield up | 28 run-over + 1 opening | 304 to 321, then quartered | 2252 |
| Mushura | shield up, reaction clips written back to 03 02 04 05 | 4 run-over + 1 opening | 304 to 320, then quartered | 390 |
- Theeder deals 284 where the shield should allow 141: twice the intended figure, and level with an unshielded cast.
- Mushura deals 2252 where the shield should allow 390: 5.8 times the intended figure, and 2.9 times an unshielded cast. Under the shield it touched Cort on 28 ticks, in five contact windows of 4, 2, 9, 8 and 5 ticks, and hit on every one. Without the shield it touched him on 38 ticks and hit 4 times, once per window.
- The control rows settle the cause. With the shield still up and only the reaction clips put back, both casts return to their normal hit counts and keep the halved rolls. The extra hits come from the blanked clips alone. The same shows on an ordinary enemy with no shield anywhere: a Gobu Gobu with its HP raised and its reaction clips written to zero took 2 Theeder hits where it normally takes 1, and 12 to 24 Mushura hits (until it died) where it normally takes 4.
- Shield goes upOn his first action Cort casts Mystic Shield. The module stores its effect handle in
0x8007BD84and zeroes Cort's reaction clips+0x1EF..+0x1F2.0x801F7678,0x801F7690 - Every hit is halvedWhile the handle is set, the damage routine halves any hit on an enemy. Measured: Theeder rolls 282 without the shield and 142 with it.
0x801DDB98 - The sweep tests for idleMushura and Theeder skip an enemy whose playing clip
+0x1D9is not zero.0x801F7870,0x801F7CF0 - The hit stages a reactionAfter the damage, the module stages a clip id taken from Cort's reaction clips - all of which the shield has set to zero.
- Still idleClip zero is the idle clip, so
+0x1D9stays zero and the next contact hits again. Captured: it read 0 at every one of the 16 Theeder and 28 Mushura tests under the shield. - Shield breaksAt half HP the per-frame pass restores the clips to
3, 2, 4, 5and clears the handle.0x8004D5C4
Register-level walkthrough
Cort's first action: his turn logic at 0x801EB988 in PROT entry 0898 queues action 0xAC while ctx[+0x28A] is zero.
Shield setup, the 0xAC body in FUN_801F7240, PROT entry 0940:
801f7678 sw v0,-0x427c(v1) ; 0x8007BD84 = effect handle
801f7690 sb zero,0x1ef(v0)
801f769c sb zero,0x1f0(v0)
801f76a8 sb zero,0x1f1(v0)
801f76b4 sb zero,0x1f2(v0)
Mushura, FUN_801F69D8 in PROT entry 0915, every tick for every enemy seat. The clip load is reached only on a tick whose range test reads contact, so each time it runs is one contact tick:
801f7844 jal 0x8004e2f0 ; range test (slot 7, seat); 0 = touching
801f7860 lhu v0,0x14c(v1) ; alive
801f7870 lbu v0,0x1d9(v1) ; playing clip
801f7878 bne v0,zero,<next> ; the only re-hit lockout
801f789c jal 0x801dd0ac ; damage roll, power 0x12
801f78f0 srl s0,s0,0x2 ; a quarter, floor 1
801f79c4 lbu v0,0x1ef(v1) ; flinch id (0x1f0 if zero)
801f79dc sb v0,0x1da(v1) ; stage it
Theeder, FUN_801F69D8 in PROT entry 0904, every tick for every enemy seat:
801f7ce0 lhu v1,0x14c(a0) ; alive
801f7cf0 lbu v0,0x1d9(a0) ; playing clip
801f7cf8 bne v0,zero,<next> ; the same lockout
801f7d0c addiu v0,v0,-0x30 ; beam bearing vs victim bearing
801f7d10 sltiu v0,v0,0xfb1 ; inside the 0x30 cone
801f7d38 jal 0x801dd0ac ; damage roll, power 0x11, not quartered
801f7df0 lbu v0,0x1f2(v1) ; get-up id non-zero: stage the knockdown id +0x1F1
801f7e0c lbu v0,0x1ef(v1) ; otherwise the flinch id (0x1f0 if zero)
801f7e24 sb v0,0x1da(v1) ; stage it
A living victim that has a get-up clip is knocked down, not flinched (0x801F7DF0..0x801F7E08). Unshielded Cort, whose clips are 3, 2, 4, 5, is staged clip 4: after Theeder's hit his +0x1D9 reads 4 for the rest of the sweep, and after each Mushura hit it reads 3.
Theeder's sweep. The sweep adds (frame step * speed scalar) << 3 to a phase word each tick (0x801F7AC8..0x801F7AF0) and ends when the phase reaches 0x1000 (0x801F7EE8..0x801F7EF4). The beam points at the summon's facing plus sin[phase] >> 4, a swing of 0x100 either side. Measured step 4 and scalar 8 give 256 a tick and 16 ticks; the two hits on shielded Cort land at phase 2048 and 4096.
Mule, FUN_801F69FC in PROT entry 0929 - the guarded sibling:
801f7e08 lbu v0,0x1d9(v1) ; the same lockout
801f7e10 bne v0,zero,<next>
801f7e34 lw v0,-0x427c(v0) ; 0x8007BD84, the shield handle
801f7e3c bne v0,zero,<next> ; shield up: no hit at all
801f7e4c jal 0x801dd0ac
Mule's guard is read from the code only. A Mule cast on shielded Cort made no damage call, but both passes that reached the lockout left at a position test just before the shield test (0x801F7E2C), so the guard itself never ran.
Why only these. Across all 64 spell and summon modules, a test of +0x1D9 sitting directly in front of a damage-roll call occurs three times: Theeder, Mushura and Mule. Every other read of that byte is a wait for an animation to finish.
The halving, FUN_801DDB30 in PROT entry 0898, 0x801DDB98..0x801DDBC8: with an enemy defender and the handle non-null, the attack value becomes def + (atk - def) / 2.
Addresses
| Address | Image | What | Evidence |
|---|---|---|---|
0x801EB988..0x801EB9B4 | PROT 0898, FUN_801E9FD4 | Cort's turn logic queues 0xAC while ctx[+0x28A] is zero | disassembly, capture |
0x801F7678 | PROT 0940, FUN_801F7240 | Shield handle stored to 0x8007BD84 | disassembly, capture |
0x801F7690..0x801F76B4 | PROT 0940 | First enemy seat's reaction clips +0x1EF..+0x1F2 zeroed | disassembly, capture |
0x801DDB98..0x801DDBC8 | PROT 0898, FUN_801DDB30 | Halve the hit on an enemy while the handle is set | disassembly, capture |
0x8004D534..0x8004D658 | SCUS_942.54, FUN_8004CE2C | Break at half HP: clips restored to 3, 2, 4, 5, handle cleared | disassembly, capture |
0x801F7870 / 0x801F789C | PROT 0915, FUN_801F69D8 | Mushura: idle test / damage roll | disassembly, capture |
0x801F78F0 | PROT 0915 | Mushura: roll quartered, minimum 1 | disassembly, capture |
0x801F79C4..0x801F79E8 | PROT 0915 | Mushura: flinch staged from +0x1EF / +0x1F0 | disassembly |
0x801F7CF0 / 0x801F7D38 | PROT 0904, FUN_801F69D8 | Theeder: idle test / damage roll | disassembly, capture |
0x801F7D0C..0x801F7D14 | PROT 0904 | Theeder: cone test, 0x30 either side | disassembly |
0x801F7AC8..0x801F7AF0 | PROT 0904 | Theeder: phase step (frame step * scalar) << 3 per tick | disassembly, capture |
0x801F7EE8..0x801F7EF4 | PROT 0904 | Theeder: sweep ends at phase 0x1000 | disassembly, capture |
0x801F7DF0..0x801F7E08 | PROT 0904 | Theeder: knockdown +0x1F1 staged when +0x1F2 is non-zero | disassembly, capture |
0x801F7E0C..0x801F7E24 | PROT 0904 | Theeder: flinch staged from +0x1EF / +0x1F0 otherwise | disassembly |
0x801F7E08 / 0x801F7E34 / 0x801F7E4C | PROT 0929, FUN_801F69FC | Mule: idle test / shield test / damage roll | disassembly |
0x801F7E2C | PROT 0929 | Mule: position test in front of the shield test | disassembly, capture |
| Monster record 180 | PROT 0867 | Cort: HP 50000, element dark, size byte 0x16 | disc data |
Scope
- Only Cort's first form (id
0xB4, scenechitei2, formation row 13) while the shield handle is set: his first 25000 of 50000 HP. - The cause is "no reaction clips", so any monster whose data supplies no reaction clips at all would be hit the same way by these two summons. That set has not been listed.
- Each extra hit also earns its own summon experience, applies its own Seru side-effect and shows its own damage number: twice for Theeder, 28 times for the measured Mushura cast.
- The shield can break in the middle of a Mushura cast. Once Cort is at or below half HP the per-frame pass restores his clips, one more hit lands on the clip that was already staged, and the rest of the cast is one hit per contact window. This was seen in one run from the first batch described under how the captures were made (the batch whose HP hold also wrote field memory before the battle), with the magic level left alone so that each hit took 2499: Cort crossed 25000 on the tenth run-over hit and the cast ended with 13.
- Mule is the opposite case by its code: under the shield its sweep is written not to hit at all.
Verifying it
The three checks, as run on the forced Cort fight:
- Execute breakpoints at
0x801F789C(Mushura) and0x801F7D38(Theeder) count 28 and 2 with the shield up, 4 and 1 once the game has broken it. +0x1D9of the actor at*(0x801C9370 + 0xC)reads 0 throughout under the shield; without it, 3 after a Mushura hit and 4 after a Theeder hit.- Writing
03 02 04 05to that actor's+0x1EF..+0x1F2with the shield up returns the counts to 4 and 1 while the rolls stay halved. The missing reaction is the cause and the shield handle is not.
Still to check: the same breakpoints in the real chitei2 fight, with three party members on screen, give Mushura's count at the real frame timing.
Open questions
- Mushura's hit count in the real fight. The measured 28 comes from a one-character party on another stage, and the count follows frame timing.
- A target that is only flinched (it has no get-up clip) and is back on idle within 32 frames is hit again at Theeder's second crossing; whether that is intended is unknown. Cort, once unshielded, is knocked down and is not.
- Which monsters, if any, ship with no reaction clips.
- Mule's shield guard has not been seen to run.