Items, stats and equipment
Five reported oversights in how Legend of Legaia handles items, stat boosts and equipment, each followed through the game's own code: stacked Speed Elixirs that lock characters out of their turns and hand turns to empty slots, story events that take equipment without telling the rest of the game, enemy items that can be turned on your own party - a Point Card that freezes the battle and a flute that kills an ally who stays standing, a Japanese coin vendor that sells a hundredth item, and a prize that can be announced and never handed over.
Speed Elixirs and void turns
- Reported as
- "Stat boost overflow": stacking Speed Elixirs in battle makes the turn-order number go negative. The character stops getting turns and "void turns" appear, where the camera swings to a spot where nobody stands and nothing happens. A dead enemy can take a turn, and the game can freeze (community report)
- Cause
- The turn-order number rolled from Speed is kept in 16 bits, and the routine that picks the next fighter reads its best-so-far as signed, so a number of 32,768 or more can never win
- Where
- Key seed
FUN_801DA780and next-actor pickerFUN_801DABA4in PROT 0898; Elixir arm0x80041464inSCUS_942.54 - Affects
- The over-boosted character and every party member seated before them; all three builds read (USA, Japanese, French)
- Status
- Explained - read from the instructions and captured on a poked state; the freeze is not traced
This entry is about Elixirs used in battle, and about Speed in particular. A Speed Elixir or a Wonder Elixir multiplies a character's battle Speed by 1.2, and nothing stops the next one from doing it again. On the USA disc the Speed stat itself is safe - it stops at 65,535. The overflow is one step further on, in the number the game rolls from Speed every round to decide who acts next.
That turn-order number is kept in 16 bits. The routine that picks the next fighter walks the seats in order and remembers the best number so far, but it reads the remembered number as signed and each new candidate as unsigned. A number of 32,768 or more therefore beats everything when it is the candidate, and then reads as negative when it is the remembered best - so the very next seat takes the lead from it, even a seat whose number is zero.
Two things follow. The over-boosted character can never be picked, and neither can anyone seated before them, because each of those lost the lead to the big number on the way past. And the round still hands out one turn per living fighter, so the turns those characters should have had go to whichever later seats are left. Once those have acted their numbers are zero, every remaining seat ties at zero, and the game draws one at random without asking whether anyone is there:
- an empty enemy slot - the void turn: the camera frames a spot with nobody in it and the turn ends at once;
- a fighter who has already acted, who gets a second action;
- a defeated enemy's slot, which the draw does not exclude.
A9E5. Seats 0 and 1 never acted; the two turns they freed went to an empty seat and to seat 2 a second time.The effect has a window. From an ordinary Speed it takes roughly 16 to 26 Elixirs on one character to open it, and a few more close it again: once Speed is pinned at 65,535 the sum wraps all the way round to an ordinary positive number and the character simply acts first.
| Battle Speed at the start | First Elixir that can lock the character out | First that always does | Elixir that reaches 65,535 |
|---|---|---|---|
| 200 | 26th | 29th | 32nd |
| 331 | 24th | 26th | 30th |
| 500 | 21st | 23rd | 27th |
| 999 | 17th | 20th | 23rd |
| 1254 | 16th | 18th | 22nd |
Speed and Wonder Elixirs count toward the same total. Which party members lose their turns depends on where the boosted one stands: in the first seat only that character is locked out, in the second seat the first two are, and in the third seat the whole party is - and then every freed turn goes to an enemy slot, living, empty or fallen.
What was captured, and how
The mechanism was read from the instructions and then observed in PCSX-Redux on the unpatched USA disc, in a battle of three party members (seats 0 to 2, Speed 331, 364 and 310) against one enemy in seat 3. These are captures on a poked state: Speed, or the turn-order number itself, was written directly in the emulator. No Elixir was used, so the Elixir routine itself was not exercised in a running game, and nobody has yet played the 24-odd Elixirs out by hand. Commands were entered by scripted pad presses (a plain attack for every member).
| What was written | Numbers, seats 0 to 3 | Turns observed |
|---|---|---|
| nothing (control) | 01ED 0186 0140 0094 | seats 0, 1, 2, 3 |
seat 0 Speed 0xFFFF | sum 0x146A9 stored as 46A9 | seat 0 acts first; an ordinary round |
seat 1 Speed 0x8000 | 01ED A9E5 0140 0094 | seat 2, seat 3, seat 5 (empty: a void turn), seat 2 a second time |
seat 0 Speed 0xFFFF and seat 1 Speed 0x8000 | 46A9 A9E5 0140 0094 | seat 2, seat 3, seat 5, seat 6 (both empty) |
seat 0 number 0xA9E5, written at the first menu | A9E5 021C 0191 0095 | seat 1 (already chosen when the number was written), seat 2, seat 3, seat 5 (empty) |
Every round lasted four turns for four living fighters, whoever took them. Not captured: a defeated enemy taking a turn (the battle had one enemy, so no fallen seat existed) and the freeze, which has been neither reproduced nor traced.
The Japanese and French builds
The picker is the same in all three builds, instruction for instruction. The Elixir routine is not: the Japanese executable has no ceiling on it, so on the Japanese disc the boosted stat itself wraps round to a small number once it passes 65,535 - an Attack of 300 is 59,077 after the twenty-ninth Power Elixir and 5,356 after the thirtieth. The USA and French builds stop the stat at 65,535. The localisation closed the stat wrap and left the picker as it was.
What it is not
The permanent stat items - the six Waters, Honey and Miracle Water - cannot overflow anything. Each adds a small fixed amount to a 16-bit number and immediately compares the result with a ceiling (999, or 9,999 for HP and 280 for agility), writing the ceiling back if it was passed. The largest value that ever exists before the compare is 1003 (10015 for HP). The Japanese and French builds carry the same compares with the same ceilings. A status-screen figure above 999 is the stored stat plus equipment, summed for display.
The instructions
The Elixir arm (class 7, 0x80041464) computes stat + stat/5 on both halfwords of a battle stat pair and stores 0xFFFF when the sum is larger (0x800414D8..0x80041510 for Speed, actor +0x164 and +0x166). There is no "already boosted" guard. Once a round the key is seeded:
801da800 lhu a0,0x164(a1) ; SPD 801da840 addu a0,a0,v1 ; + rand() % (SPD/2 + 1) 801da844 addiu a0,a0,1 801da84c sh a0,0x16c(a1) ; 16-bit store, no ceiling
The wounded bonus, the halving under Slow (0x801DA908) and Speed Chain's +0x1000 (0x801DAA08) are 16-bit too. The picker starts with seat 0's key as the running maximum and walks seats 1 to 6:
801daca4 sll v0,a1,0x10 801daca8 lhu v1,0x16c(v1) ; candidate key, zero-extended 801dacac sra v0,v0,0x10 ; running maximum, sign-extended 801dacb0 slt v0,v0,v1 ; (signed) max < (unsigned) candidate? 801dad60 sb v0,0x274(a1) ; the chosen seat
A passing test makes the candidate the maximum and restarts the tie list; equality (0x801DACD8) adds the seat to the list; the result is a random member (jal rand at 0x801DAD0C). A key of 0x8000 or more always passes as a candidate and always loses as the maximum, and the equality test never matches it. The loop has no HP test, no "is this slot populated" test and no "key is not zero" test.
The turn start (0x801E2C50..0x801E2D54 in FUN_801E295C) takes the seat from ctx[+0x274] unchecked, loads the actor pointer from 0x801C9370[seat], zeroes its key and calls the camera framing routine (jal 0x801d5854). Unused enemy seats still have zero-filled actor records, so the camera frames an empty seat and the turn falls through to its end.
From the seed formula: below Speed 21,845 the key is always under 0x8000; from 21,845 to 32,766 it passes 0x8000 on some rolls; from 32,767 to 43,689 on every roll; from 43,690 to 65,534 the sum increasingly passes 0xFFFF and wraps back; at 65,535 the key is rand() % 0x8000.
The Japanese Elixir arm (0x800425F0..0x8004295C in SCPS_100.59) ends in a plain store with no compare: lhu v0,0x164(a0) at 0x80042608, addu v1,v1,v0 at 0x80042620, sh v1,0x164(a0) at 0x80042624.
The permanent items are class 6, arm 0x8004112C; the tier byte picks one of seven arms through the table at 0x800151B0, all of this shape:
800411e8 lhu v0,0x6ec(v1) ; stored ATK (record +0x124) 800411f0 addiu v0,v0,0x4 800411f4 sh v0,0x6ec(v1) 800411fc sltiu v0,v0,0x3e8 ; below 1000? 80041200 bne v0,zero,<exit> 8004120c _sh v0,0x6ec(v1) ; otherwise store 999
The item menu then rebuilds the live stats (jal 0x80042558 at 0x801D8540, PROT 0899), which clamps again at 0x80042C0C..0x80042CE0. One enemy move does wrap a stat - Jugger Power (cast 0xBA, PROT 0945) adds a quarter to ten stat halfwords at 0x801F6DA0..0x801F6E34 with no compare - but it is an enemy self-buff and unrelated to Elixirs.
| Address | Image | What | Evidence |
|---|---|---|---|
0x800402F4 | SCUS | Item applier; class table 0x80014FA0 | disassembly |
0x80041464 | SCUS | Elixir arm; Speed pair 0x800414D8..0x80041568, ceiling 0xFFFF | disassembly |
0x800425F0 | SCPS_100.59 (Japan) | Elixir arm, through 0x8004295C; no ceiling | disassembly |
0x80041E24 | SCES_019.44 (France) | Elixir arithmetic, with the 0xFFFF ceiling | disassembly |
actor +0x164, +0x166, +0x16C | RAM | Battle Speed (working, base); turn-order key | disassembly |
0x801DA780 | PROT 0898 | Key seed; 16-bit store at 0x801DA84C | disassembly |
0x801DA84C | PROT 0898 | Sum 0x146A9 stored as 0x46A9; 0xA9E5 stored from Speed 0x8000 | capture (poked Speed) |
0x801DA908, 0x801DAA08 | PROT 0898 | Slow halving and Speed Chain +0x1000, both 16-bit | disassembly |
0x801DABA4 | PROT 0898 | Next-actor picker; mixed compare at 0x801DACA4..0x801DACB0 | disassembly |
0x801DAD60 | PROT 0898 | Result store; empty seats 5 and 6 drawn, seat 2 drawn twice | capture (poked Speed or key) |
0x801E2C50 | PROT 0898 | Turn start, through 0x801E2D54: seat taken unchecked, camera call | disassembly |
0x801DDBFC, 0x801DE048 | Japanese PROT 0898 (base 0x801D05C8) | Key seed; picker compare through 0x801DE080 | disassembly |
0x801DB524 | French PROT 0898 (base 0x801CF0A8) | Picker compare, through 0x801DB55C | disassembly |
| one turn per seated fighter, less the skipped | PROT 0898 | 0x801E679C..0x801E67E4: the end-of-action gate bumps the turn cursor ctx[+0x1A] and continues the round while it is below ctx[+0] + ctx[+1] - ctx[+0x25] (party seats plus monster seats, less the fighters the order dropped without acting) | disassembly |
0x801F69D0 | RAM | Turns begun this round: zeroed at 0x801E2ABC and 0x801E2E08, incremented at 0x801E2C38; its one read (0x801E2B9C) is a zero test that picks a camera yaw step, so it does not hand out turns | disassembly |
| a defeated enemy taking a turn; the freeze | - | The draw admits any seat with key 0; neither was captured | community report |
0x8004112C | SCUS | Permanent stat-up arm; tier table 0x800151B0 | disassembly |
0x80041178 | SCUS | Life Water: record +0x11C +16, ceiling 9999 | disassembly |
0x800411C4 | SCUS | Power Water: +0x124 +4, ceiling 999 | disassembly |
0x800413F4 | SCUS | Guardian Water: +0x126 and +0x128 +4, ceiling 999 | disassembly |
0x80041210 | SCUS | Swift Water: +0x12A +4, ceiling 999 | disassembly |
0x8004125C | SCUS | Wisdom Water: +0x12C +4, ceiling 999 | disassembly |
0x800412A8 | SCUS | Magic Water: +0x11E +8, ceiling 999 | disassembly |
0x800412F4 | SCUS | Honey / Miracle Water: +4 to eight fields, AGL ceiling 280 | disassembly |
0x800420F4, 0x80041A9C | SCPS_100.59, SCES_019.44 | Japanese and French permanent stat-up arms, same ceilings | disassembly |
0x8003FB10 | SCUS | Usability check that greys an item nobody can benefit from | disassembly |
0x80042558 | SCUS | Live-stat rebuild; clamps at 0x80042C0C..0x80042CE0 | disassembly |
0x801F6DA0 | PROT 0945 | Jugger Power stat block, through 0x801F6E44 | disassembly |
Verifying it
On a poked state: at the entry of 0x801DA780, write 0x8000 to +0x164 and +0x166 of the party member in seat 1. A breakpoint at 0x801DA84C shows a0 between 0x8001 and 0xC001; a breakpoint at 0x801DAD60 never shows seat 0 or seat 1 as the result, and shows an empty seat once seats 2 and up have acted. Unpoked, use Speed Elixirs on one character up to the count in the table and watch the same two breakpoints.
Still open: the freeze (a battle with one enemy already defeated and a later-seated party member in the lock-out band would show where the action state stops); and a played reproduction with real Elixirs. Related reference: item-effect table, battle action state machine, battle formulas.
Story equipment removal skips the re-check
- Reported as
- When the plot takes a piece of equipment, its bonus keeps working until something else re-checks equipment (community report)
- Cause
- The script's take-item instruction empties the equipment slot but never calls the routine that turns slots into bonuses
- Where
- Field script instruction
4C 52at0x801E1ABC(PROT 0897) andFUN_800430ACinSCUS_942.54 - Affects
- Nine story hand-overs of a wearable item, listed below, when the item is equipped at that moment
- Status
- Explained - the mechanism and the nine sites; how long the stale bonus lasts is only partly traced
An accessory's effect is not looked up when it is needed. One routine "bakes" it into each character: it reads the eight equipment slots and writes out a set of ability bits and a block of live stats. Battle, the random-encounter roll and the menus all read the baked copy, never the slots.
When the story takes an item, the script instruction first tries the bag. If the item is not there because it is being worn, it clears the equipment slot directly - and stops. It does not run the bake, so the baked copy still says the item is on.
The game does have a script instruction that writes an equipment slot and re-bakes; it is the one that grows the Ra-Seru. The take-item fallback simply does not use it.
| Item | Effect left behind | Scene | Script location (PROT / record / offset) |
|---|---|---|---|
Yuma's Ring (0xAF) | Max MP +10% | Jeremi (geremi) | 166 / P2[16] / +0x0109 |
Earth Egg (0x6E) | Earth Guard | Jeremi | 166 / P2[19] / +0x1056 |
Water Egg (0x6F) | Water Guard | Jeremi | 166 / P2[19] / +0x1192 |
Light Egg (0x70) | Light Guard | Jeremi | 166 / P2[19] / +0x12CE |
Dark Stone (0x71) | Dark Guard | Jeremi | 166 / P2[19] / +0x1409 |
Ra-Seru Egg (0xAB) | Thunder Guard | East Voz Forest (vozz) | 104 / P2[17] / +0x01D7 |
Star Pearl (0xAE) | INT +5% | Shadow Gate (stone) | 175 / P1[4] / +0x018D |
Nemesis Gem (0xB5) | High Encounter (whole party) | Jette's Fortress entrance (deroa) | 606 / P2[4] / +0x03D4 |
Fire Droplet (0xBC) | Maximum AP | Usha Research Center (doman, variant script) | 401 / P1[15] / +0x1F82 |
The list is computed, not picked: every take-item instruction on the disc was decoded, and these nine are the ones whose item carries a wearable effect. All the others take key items or consumables and leave nothing behind.
How long it lasts
Until the next event that re-bakes. Entering any scene always does. So do using an item or magic from the menu, equipping or removing anything, Best Equipment, and buying-and-equipping in a shop. The field scene is reloaded after a battle, which would limit the stale bonus to a single battle fought before leaving the room; that part rests on the engine documentation and was not re-read. The in-field save screen does not re-bake. Whether simply closing the pause menu does is not traced.
The instructions
801e1ac4 lbu a0,1(s6) ; item id 801e1ac8 jal 0x80042310 ; remove one from the bag 801e1adc bne v0,v1,0x801e00b8 ; found in the bag: done 801e1ae8 jal 0x800430ac ; not in the bag: unequip it 801e1af0 j 0x801e3628 ; exit - no jal 0x80042558
FUN_800430AC walks each party member's three accessory slots (record +0x19B..+0x19D), zeroes the first match with sb zero,0x196(v1) at 0x80043108 and returns. It has one caller on the disc.
The rebuild FUN_80042558 zeroes the ability words at 0x800425EC, walks the slots at 0x80042620..0x8004270C, applies the percentage boosts and clamps. Every reference to it on the disc is a call, and none is in the battle program. The instruction that does it properly is 0x3B at 0x801E07DC: jal 0x80042558 at 0x801E0810 with the slot store sb v1,0x75e(v0) in its delay slot.
| Address | Image | What | Evidence |
|---|---|---|---|
record +0x196..+0x19D | RAM | Equipment slots; the last three are the accessories | disassembly |
record +0xF4..+0x103 | RAM | Ability bits, one per effect | disassembly |
record +0x104..+0x11A | RAM | Live stats (stored base at +0x11C..+0x12C) | disassembly |
0x80074358 | SCUS | Party-wide ability mask | disassembly |
0x80042558 | SCUS | The rebuild | disassembly |
0x801E1ABC | PROT 0897 | Take-item instruction 4C 52 | disassembly |
0x80042310 | SCUS | Bag remove; returns 0x100 when absent | disassembly |
0x800430AC | SCUS | Unequip by id, no rebuild | disassembly |
0x801E07DC | PROT 0897 | Instruction 0x3B: equipment-slot write with rebuild | disassembly |
0x8003B2B8 | SCUS | Rebuild call in the scene-entry routine FUN_8003AEB0 | disassembly |
0x80024378 | SCUS | Save-screen driver reloading the field program with no scene init | disassembly |
| the nine sites above | PROT scene scripts | Decoded take-item instructions joined to the item table | disc data |
| scene reload after battle | - | Bounds the stale bonus to one battle | repo doc |
Verifying it
Equip Yuma's Ring on Vahn: 0x800847FC has bit 0x4 and the live max MP at 0x80084810 is 110% of the stored one at 0x80084826. Give the ring to Zalan. Straight afterwards the slot bytes at 0x800848A3..0x800848A5 hold no ring, but the bit and the live max MP are unchanged. A breakpoint on 0x80042558 that logs the caller shows which event finally clears it. Related reference: accessory passives, field script VM.
Enemy items aimed at an ally
- Reported as
- An enemy-targeted battle item can be aimed at one of your own characters. The Point Card then hangs the battle (the "Point Card softlock"); the Lippian Flute can kill an ally who stays on their feet ("Lippian Roulette"). Outcome matrix from a community report by ZetaPhoenix
- Cause
- The target cursor can step onto an ally. The Point Card's damage skips the HP-counter bookkeeping the end of the action waits on; Lippian's kill runs a fade that stands a party member back up at 0 HP
- Where
- Item window at
0x801D18F8and the action state machine in PROT 0898; discharge arm0x8004209Cand fade arm0x80050230inSCUS_942.54; Lippian cast moduleFUN_801F6A18in PROT 0924 - Affects
- The Point Card and the Lippian Flute, aimed at any party member. Not the Spikefish Flute, which hits every enemy and never opens a cursor
- Status
- Explained - read from the instructions, matched against the community matrix and captured on a poked state
Two items in the game are meant for one enemy and nobody else: the Point Card and the Lippian Flute. Both can be pointed at your own party, and each does something its designers never drew.
The cursor can reach an ally. When you pick one of these items, the game builds a ring of targets that starts from whoever this character aimed at last. It builds the ring first and only afterwards checks that the last target was an enemy. If the last thing this character did was aimed at an ally - any healing item or Elixir, whose cursor starts on the user - that ally is already in the ring. The cursor is moved to an enemy, but one press of Left steps back onto the ally.
The Point Card breaks the HP display. Its damage routine subtracts HP and does nothing else. Every other routine that changes a party member's HP also notes how far the on-screen number still has to count. At the end of an action the game holds, slowly turning the camera, until on-screen HP equals real HP. Here they differ and nothing is counting, so the hold never ends: the "Points returned" caption stays up, the HP bar keeps its old value and the camera circles for good.
Lippian's kill is written for a monster. It sets HP to 0, starts the target's knockdown and switches on the fade a defeated monster disappears with. On a party member that same fade is the one a revive uses: the body goes black, is put back in its standing pose and fades in again. HP stays at 0, so the character is dead in every way except how they look.
The Point Card hang is the same end state as the first of the two known battle softlocks - the HP-counter wait - reached from the controller on an unmodified disc. It is not the approach softlock described in the endless camera orbit.
What happens, case by case
Each cell says where it comes from: C a community report (ZetaPhoenix, in game), D the disassembly, P a capture on a poked state, described below.
| Item | Condition | Living ally | Dead ally |
|---|---|---|---|
| Point Card | holds points | Battle hangs: the camera orbits for ever. Lethal or not. (C, D, P) | No hang; the points are still spent. (C, D, P) |
| Point Card | no points | Nothing; the turn is used. (C, D, P) | Nothing. (C, D) |
| Lippian Flute | kill roll fails | Nothing; the flute is used up. (C, D, P) | Nothing. (C, D, P) |
| Lippian Flute | kill roll lands | HP goes to 0 but the ally stands back up. (C, D, P) | The body stands up, still at 0 HP. (C, D, P) |
- The dead-ally column holds only when the item user is the first fighter to act that round. For anyone acting later the game re-rolls a dead target among the living party members, the user included, and the living-ally column applies to whoever it picks (D, P).
- Point Card on a dead ally is not quite nothing. The whole bank, up to 9999 points, is spent, a damage number is shown and the body replays its collapse. Nothing hangs because real and on-screen HP are both 0 (D, P).
- The Point Card itself is never used up. It leaves the bag when you confirm and is added back when the action starts. The Lippian Flute is consumed (D, P).
- The kill roll is 1 in 128, not 1 in 126: a random number's low seven bits must all be zero. The number 126 does appear on the item, as the effect class of its descriptor, which is not a probability (D).
- A standing character at 0 HP is dead to the rules. The command ring skips them, and when the last living member is "killed" this way the battle ends in the ordinary defeat message with the character upright (D, P).
Which items can do this
The Item window looks at two flags on the item: "enemy side" and "all targets". Only "enemy side, one target" opens the cursor whose ring is built too early.
| Item | Id | Descriptor | Target | Reaches an ally |
|---|---|---|---|---|
| Point Card | 0xFE | 01 00 C4 41 | one enemy | yes |
| Lippian Flute | 0x98 | 7E 00 C4 41 | one enemy | yes |
| Spikefish Flute | 0x99 | 7F 00 E4 41 | all enemies | no: no cursor is opened |
Those are the only three consumables with the enemy-side flag. Two more descriptor rows carry the flute classes (7E 00 C6 41 and 7F 00 E6 41), and no consumable uses either. The game's own code names the same pair: the routine that re-aims an action whose target has died tests the item id against 0xFE and 0x98 and nothing else.
- Aim at an allyA healing item or Elixir leaves an ally seat in the actor's target byte
+0x1DD. - Pick the Point Card or the Lippian FluteThe ring is built at
0x801D18F8; the enemy check comes after, at0x801D1918. - Press LeftThe cycler
FUN_801D8D00returns the ring head: the ally. - Point Card: the hit landsArm
0x8004209Clowers HP and seeds no countdown, so state0x51asksFUN_801E7250every frame and is always told "not settled". - Lippian Flute: the rollOne chance in 128 at
0x801F6B14. On a miss the target is only tinted. - Lippian Flute: the kill
0x801F7684zeroes HP, seeds the countdown and sets the fade; the fade arm at0x80050348puts a party member back in the standing pose.
The instructions
801d18f8 jal 0x801d8a88 ; build the target ring 801d1918 lbu v0,0x1dd(v0) ; only now read the stored target 801d1924 sltiu v0,v0,5 ; a monster seat (3..7)? 801d1930 jal 0x801db8b4 ; if not: first living monster
The Magic window runs the same two steps in the right order (check at 0x801D1C8C, build at 0x801D1CC0). The builder stores the unchecked target as the ring head with sb v0,0x245(v1) at 0x801D8B30. The picker stores the cycler's answer at 0x801D2630 and its confirm path never re-checks it. At a round boundary a stored target is replaced only when it names a dead seat (0x801D8A00..0x801D8A54), so a living ally stays stored from turn to turn.
801e4084 addiu v0,zero,0xfe ; item 0xFE? 801e40bc addiu v0,zero,0xe 801e40c0 sb v0,0x1e8(s3) ; applier selector = 0x0E
The discharge arm leaves at 0x800420AC when the bank at 0x800845B4 is empty. Otherwise it spends min(bank, 9999), queues a reaction clip and writes HP at 0x8004219C, clamped at 0, without ever looking at the target first. It writes neither the countdown at actor +0x10 nor the displayed HP at +0x172; the heal and revive arms of the same routine do, at 0x800408FC, 0x80040D28 and 0x800410BC. The settle check compares +0x14C with +0x172 at 0x801E72A8..0x801E72B4, and state 0x51 turns the orbit angle every frame at 0x801E6024 while it waits. On a dead target both values are 0, so nothing hangs. The card comes back to the bag at 0x801F3A58.
801f6b14 andi v0,v0,0x7f ; kill only when the low seven bits are zero 801f7684 lbu v1,0x1f1(s3) ; the victim's knockdown clip 801f7688 lhu t0,0x14c(s3) ; its HP 801f7690 sb v0,0x225(s3) ; = 2 801f7694 sb v0,0x21c(s3) ; = 2, the defeat fade 801f76a0 sh zero,0x14c(s3) ; HP = 0 801f76a4 sb v1,0x1da(s3) ; stage the knockdown 801f76bc sw v1,0x10(s3) ; countdown += old HP
The cast module reads its victim from the caster's target byte on every tick (0x801F6A68) and never asks which side it is on. Because the countdown is seeded here, the HP number counts to 0 and the action ends normally. The fade is arm 2 of the per-actor presentation tick FUN_80050120: a non-zero +0x225 starts it at once, and when a party seat reaches black it stores +0x21C = 0, +0x1DA = 0 (the standing clip) and +0x1DC = 1 at 0x80050348..0x80050350. The revive arm of the item routine is what normally sets +0x21C = 2 on a party member (0x800410D0), after it has restored HP.
801db1e0 li v0,0xfe 801db1ec beq v1,v0,0x801db1fc ; Point Card 801db1f0 li v0,0x98 801db1f4 bne v1,v0,0x801db300 ; anything but the Lippian Flute: leave it 801db1fc sltiu v0,a1,0x3 ; is the dead target a party seat?
That is the dead-target redirect FUN_801DB124. A dead party seat is replaced by a random living party seat (0x801DB210..0x801DB274). It is called from the turn picker only while the command-flow byte reads 0xFF (0x801DAF04), and the round's first fighter is picked earlier than that, from the menu half of the battle (0x801D0E8C, 0x801D0ED8). So the first fighter of a round is never re-aimed and every later one is.
| Address | Image | What | Evidence |
|---|---|---|---|
0x800845B4 | RAM | Point Card bank | disassembly |
0x80074F50, 0x800754B8 | SCUS | Item 0xFE record and its descriptor | disc data |
0x80074A88, 0x8007535C | SCUS | Item 0x98 record and its descriptor | disc data |
0x80074A94, 0x80075360 | SCUS | Item 0x99 record and its descriptor | disc data |
0x801D18E0 | PROT 0898 | Item window, enemy single-target arm | disassembly |
0x801D8A88 | PROT 0898 | Ring builder; head store 0x801D8B30 | disassembly |
0x801D8D00 | PROT 0898 | Ring cycler | disassembly |
ctx[+0x244..+0x248] | RAM | Ring count, head, three more seats | disassembly |
0x801D23F0 | PROT 0898 | Target picker; store at 0x801D2630 | disassembly |
0x801D19A0 | PROT 0898 | Ally-item arm seeding the user's own seat | disassembly |
0x801DB124 | PROT 0898 | Dead-target redirect; item-id tests at 0x801DB1E0 | disassembly |
0x801DAF04 | PROT 0898 | Turn picker's gate on the redirect for a party seat | disassembly |
0x801F3A58 | PROT 0898 | Point Card handed back to the bag | disassembly |
0x801E4080 | PROT 0898 | Action state 0x3E: selector override for item 0xFE | disassembly |
0x801E4134 | PROT 0898 | Action state 0x3F: call into the applier | disassembly |
0x8004209C | SCUS | Point Card discharge arm, through 0x8004219C | disassembly |
0x801E7250 | PROT 0898 | HP-counter settle check | disassembly |
0x801E6044 | PROT 0898 | Action state 0x51 gate; orbit step at 0x801E6024 | disassembly |
0x801F6B0C | PROT 0924 | Lippian kill roll; flag at 0x801F7C4C | disassembly |
0x801F7684 | PROT 0924 | Lippian kill writes on the victim, through 0x801F76BC | disassembly |
0x80050230 | SCUS | Fade arm; party-seat completion at 0x80050348 | disassembly |
0x800410D0 | SCUS | Revive arm setting +0x21C = 2 | disassembly |
actor +0x10, +0x14C, +0x172, +0x1DD | RAM | Countdown, real HP, on-screen HP, target seat | disassembly |
actor +0x1DA, +0x1F1, +0x21C, +0x225 | RAM | Staged clip, knockdown clip id, presentation arm, fade-now byte | disassembly |
What was captured
The probe scripts/pcsx-redux/autorun_enemy_item_ally_target.lua runs on a catalogued save state with three members on the first command screen of a battle. The cursor path is the real one: it presses Begin, opens the Item window, picks the item, presses Left and confirms. Written by hand once beforehand: the item into the first bag slot, the Point Card's points, the user's stored target (the stale ally a healing item leaves), and 0 HP plus a staged knockdown on the two members who are not the user, so that they are lying dead when the walk starts. For the flute rows the kill flag is forced, since the roll is 1 in 128.
| Run | Logged |
|---|---|
| The ring, every run | Ring head is the ally seat; Left moves the target byte from 3 to the ally |
| Point Card, 50 points, user on self | Bank 50 to 0, HP 3437 to 3387, on-screen 3437, countdown 0; knockdown, get-up; state 0x51 to the end of the run |
| Point Card, 9999 points, user on self | HP 0, on-screen 3090; collapse, then standing again at state 0x51; the same hang |
| Point Card, 0 points, user on self | Nothing written to the target; the round goes on to the monster's turn |
| Point Card, 50 points, dead ally, user first | Bank 50 to 0; target HP and on-screen HP both 0; the body replays its collapse; no hang |
| Point Card, 50 points, dead ally, user not first | Target re-rolled to the living user when the turn is picked, then the hang |
| Lippian, kill forced, user on self | HP 3090 to 0, countdown 3090 draining to 0; knockdown, collapse, standing; defeat follows |
| Lippian, kill forced, dead ally | Lying, knockdown, collapse, standing; HP 0 throughout; the round goes on |
| Lippian, roll forced to fail | No HP, clip or countdown change on the target, living or dead |
| Card and flute counts | The card goes 3, 2 at confirm, 3 when the action starts; the flute goes 3, 2 and stays |
In the hang the screenshots show the "Points returned" caption still up, the HP bar at its old value and the camera at a different angle each time. In the kill-on-self runs the user is the last living member, so the standing character is followed by the party-defeat message and the title screen.
One detail explains an older report that the character is "revived" before the freeze. A lethal Point Card hit on the user's own seat shows the character collapse and stand up again: the end-of-action cleanup tells the acting character to return to the standing pose when its current clip ends. The HP bar still shows the old value, and the battle still hangs.
Verifying it
Use a healing item on the acting character, or open and cancel its ally cursor. Next turn pick the Point Card or the Lippian Flute and press Left: a breakpoint at 0x801D2630 shows a seat of 0, 1 or 2.
- Point Card: confirm, then watch the action state byte sit at
0x51with its timer frozen at0x3C, the target's+0x14Cdifferent from its+0x172and its+0x10zero. Writing+0x172 = +0x14Cby hand releases the battle. - Lippian Flute: write a non-zero word to
0x801F7C4Conce the cast's phase bytectx[+0x279]has left 0. At0x801F76A0registers3is the ally's actor. Afterwards its+0x14Cis 0 and its playing clip+0x1D9is 0. - Redirect: break on
0x801DB260. It is hit only when the user is not the round's first fighter.
Related reference: battle action state machine, item-effect table.
Open: whether a revive item works normally on a member left standing at 0 HP, and whether monsters still pick that seat; how a dead ally comes to be the stored target at command time (the round-boundary pass replaces a dead one); other builds were not read for this entry.
War God Icon can be missed for good
- Reported as
- The War God Icon is lost for good if the Muscle Dome Expert Course is beaten before defeating Jette (community report)
- Cause
- The item and its "already awarded" flag are handed out by two different pieces of code that disagree about what clearing the course means
- Where
- Arena settlement
FUN_801D0F60in PROT 0977; lobby victory scene, record P2[9] of scenekoin1(PROT 543) - Affects
- The Master course - not Expert as reported - won while it is still shortened
- Status
- Explained - from the instructions and the scene script; not run
The prize is split in two. The item is added by the arena program, and only when the contest ended on its thirteenth fight and an "already awarded" flag is clear. The flag is set by the lobby's victory scene, which only asks: was this a Master contest, and was it won?
Early in the story the Master course is cut short to 8, 11 or 12 fights. Winning the shortened course is still a win as far as the victory scene is concerned, so it sets the flag and plays the presentation - the announcer names the Icon. But the arena saw fewer than thirteen fights and added nothing. From then on the flag is set, and the arena skips the item every time, including after a full thirteen-fight win.
The last of the three story flags that lengthen the course is set inside Jette's Fortress. That is where "before defeating Jette" comes from.
| Story flag | Course length while it is clear | Set by |
|---|---|---|
0x378 | 8 fights | map03 P2[15] and scripts in nine other scenes |
0x382 | 11 fights | Scripts in eleven scenes |
0x471 | 12 fights | chitei2 P1[0] only (Jette's Fortress), after a staged fight that precedes the Jette fight |
The tests overwrite one another in order, so the last missing flag decides: with all three missing the course runs 12 fights.
The instructions and script bytes
801ced44 jal 0x8003ce64 ; flag 0x378 missing: length 8 801ced6c jal 0x8003ce64 ; flag 0x382 missing: length 11 801ced94 jal 0x8003ce64 ; flag 0x471 missing: length 12 801d111c slti a1,a1,0xd ; round reached below 13? 801d1124 bnez a1,0x801d1148 ; yes: no item 801d112c jal 0x8003ce64 ; flag 0x6CB 801d1134 bnez v0,0x801d114c ; set: no item 801d1140 jal 0x800421d4 ; War God Icon (item 0xCD) x1
The arena never sets 0x6CB. A win sets flag 0x50A at 0x801D101C, and the lobby's winner scene is gated on that flag. In that scene, at record +0x0369, 76 CB tests 0x6CB and 75 38 tests the Master-chosen flag 0x538; the target at +0x03E1 begins with 56 CB, set 0x6CB. The item appears there as a name in the text only - the record contains no give-item instruction - and neither test looks at the number of fights. No instruction on the disc clears 0x6CB.
| Address | Image | What | Evidence |
|---|---|---|---|
koin1 P1[9] +0x0B6F | PROT 543 | Master row of the course menu; sets flag 0x538 | disc data |
0x801CED28 | PROT 0977 | Course-length overrides, through 0x801CEDA4 | disassembly |
0x801CEE10 | PROT 0977 | Win latch store (0x801D1ADC) | disassembly |
0x801D1A90, 0x801D1A94 | PROT 0977 | Course index, round reached | disassembly |
0x801D0F60 | PROT 0977 | Settlement; item test 0x801D111C..0x801D1144 | disassembly |
koin1 P1[0] +0x0181 | PROT 543 | Lobby dispatch of the result scenes | disc data |
koin1 P2[9] +0x0369 | PROT 543 | The two flag tests | disc data |
koin1 P2[9] +0x03E1 | PROT 543 | Set flag 0x6CB | disc data |
0x80085831 bit 0x10 | RAM | Flag 0x6CB: Icon presented | disc data |
0x800857FF bit 0x80 | RAM | Flag 0x538: Master chosen | disc data |
0x800857F9 bit 0x20 | RAM | Flag 0x50A: contest won | disassembly |
0x800857C7 bit 0x80 | RAM | Flag 0x378 | disassembly |
0x800857C8 bit 0x20 | RAM | Flag 0x382 | disassembly |
0x800857E6 bit 0x40 | RAM | Flag 0x471 | disassembly |
Verifying it
From a save with flag 0x471 clear, win the Master course. It ends after fight 12; a breakpoint at 0x801D1124 shows the branch taken and the item add skipped; after the lobby scene, byte 0x80085831 has bit 0x10 set. The counter-test: clear that bit, set 0x471, win thirteen fights, and the item arrives. Clearing bit 0x10 at 0x80085831 should repair an affected save.
Open: whether the party can leave Jette's Fortress between the last flag being set and the Jette fight was not checked.