data/claims/lufia-ii.yamlLufia II's battle rules (Cellenseres's decompilation and vinheim3's disassembly, USA ROM)
Each enemy shown on a field map stands for an enemy group the map lists: when the map places an encounter actor, the game takes the actor's slot, reads the group in that slot of the map's encounter list, and sets up that slot's enemies from it. In the Ancient Cave the list is read from memory, where the cave writes it, rather than from the ROM. lufia-ii/field-encounter-slots
About: Lufia II: Rise of the Sinistrals Visible encounter
Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) ·code/bank_000.s#L7040-L7053lda $94ddf6.l, X ; $ab86 : $bf, $f6, $dd, $94
ldx wCurrPuzzleScript ; $ab8a : $a6, $a7
sta wCharacterType.l, X ; $ab8c : $9f, $d2, $05, $00
stz $0736.w, X ; $ab90 : $9e, $36, $07
lda $54 ; $ab93 : $a5, $54
sta wCharacterIds.l, X ; $ab95 : $9f, $fa, $05, $00
sec ; $ab99 : $38
sbc #$4f.b ; $ab9a : $e9, $4f
pha ; $ab9c : $48
jsr LoadNPCsLocAndMovementArea.l ; $ab9d : $22, $1d, $c0, $80
jsr SetNPCsLocation.l ; $aba1 : $22, $a7, $c1, $80
pla ; $aba5 : $68
…Our readingthe actor's sprite from the encounter sprite table at $94:DDF67040–7042slot = the actor's id − $50 @7044-7048, 7051-7052load its location and movement area, and place it7049–7050fill the enemy slot7053lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_001.s#L435-L497; A - enemy setup slot idx, must be 1+
FillAnEnemySetupSlot:
php ; $8351 : $08
phb ; $8352 : $8b
rep #ACCU_8|IDX_8 ; $8353 : $c2, $30
pha ; $8355 : $48
phx ; $8356 : $da
phy ; $8357 : $5a
sep #ACCU_8 ; $8358 : $e2, $20
cmp #$20.b ; $835a : $c9, $20
bcc + ; $835c : $90, $01
; todo: unknown
…Our readinga slot of 32 or more runs into a $00 byte444–447start slot × 10457–460if the room is $F0 (the Ancient Cave): group = $7F:F966[slot] @463-466, 480-482else: group = $97:B9AC[offset[room] + slot]468–478X = slot × 10; add the enemy setup (A = group, X = the slot's offset) @484-485, 495-497Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/field_encounter_selection.c#L7-L44enum {
DP_ENCOUNTER_SLOT = 0u,
ROM_MAP_ENCOUNTERS = 0xb9acu,
CAVE_ENCOUNTERS = 0x7ff966u,
ANCIENT_CAVE_MAP = 0xf0u,
ENCOUNTER_SLOT_COUNT = 32u,
ENCOUNTER_RECORD_BYTES = 10u
};
static void SelectFieldEncounter(const Lufia2Memory *memory, Lufia2CpuState *cpu) {
OpSta(memory, cpu, OpDp(cpu, DP_ENCOUNTER_SLOT));
OpStz(memory, cpu, OpDp(cpu, DP_ENCOUNTER_SLOT + 1u));
OpLoadA(cpu, 0x97u);
…Checked by claude, 2026-11-08 — read the slot routine and its caller in the actor setup loop in the disassembly, and the decompilation's version of the slot routineRevised after a check by a second AI model, 2026-11-08.The slot routine is $81:8351 and the setup it calls $81:839F; the actor-setup call is at $80:ABA7. The ROM list at $97:B9AC is a table of word offsets by room, then each room's group numbers; Terror Wave names it MapFormationsObject. The cave's list is at $7F:F966.
Cited by: Random encounter, Visible encounter
How battles start on Lufia II's world map, and at what rate, isn't read yet. lufia-ii/world-map-encounters
About: Lufia II: Rise of the Sinistrals Random encounter
UnsourcedLufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) ·src/world/world_scene.c#L1592-L1617static void SaveEncounterView(const Lufia2Memory *memory,
Lufia2CpuState *cpu) {
OpLoadA(cpu, 1u);
OpSta(memory, cpu, OpAbs(cpu, 0x11ddu));
OpLoadA(cpu, 0xffu);
OpSta(memory, cpu, OpAbs(cpu, WORLD_MAP_MODE));
OpLdy(cpu, OpReadX(memory, cpu, OpAbs(cpu, 0x1202u)));
OpWriteX(memory, cpu, OpAbs(cpu, 0x1210u), cpu->y);
OpLdy(cpu, 0u);
OpWriteX(memory, cpu, OpAbs(cpu, 0x1212u), cpu->y);
static const uint16_t fields[][2] = {
{0x11fcu, 0x1214u}, {0x11feu, 0x1216u}, {0x1200u, 0x1218u}
…Revised after a check by a second AI model, 2026-11-08.Cited by: Random encounter
Once an action isn't rejected by the target's status or interrupted, its damage is a base value scaled, given a random bonus, cut by half the target's defense, halved, and trimmed by a factor: X = base × scale / 16; X + X × v / 256, with v random from 0 to the action's variance − 1; less half the target's defense, at least 0; halved; then less X × F / 256, where F is the action's damage-factor byte. First a roll from 0 to 99 is made against the action's chance byte: below it, the action's own scale stands and the target's defense counts as 0, a heavier hit that ignores defense; otherwise the scale is 16, times 1. Healing takes the scale and the random bonus only. A scaled base past 65,535 runs into a $00 byte in the code rather than a result. The base, chance, scale, variance, defense, and factor come from the action's battle script, which isn't read here, and the lines read hold no miss test. lufia-ii/damage
About: Lufia II: Rise of the Sinistrals Damage formula
CodeLufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) ·src/battle/battle_target_action.c#L717-L798Lufia2ExecutionResult Lufia2BattleApplyTargetAction(const Lufia2Memory *memory,
Lufia2CpuState *cpu,
Lufia2PushedChildCall child,
void *context) {
const uint8_t bank = cpu->data_bank;
if (!child || cpu->program_bank != 0x85u || cpu->direct_page || cpu->decimal ||
!cpu->accumulator_is_8_bit || cpu->index_is_8_bit || cpu->stack < 0x1f20u ||
cpu->stack > 0x1ffcu || !(bank < 0x40u || (bank >= 0x7eu && bank < 0xc0u)))
return ExecutionHandoff(cpu, 0x85d0cdu);
OpLda(memory, cpu, OpAbs(cpu, WRAM_BATTLE_ACTION_WORK_BYTE));
OpSta(memory, cpu, OpAbs(cpu, ACTION_RESULT));
OpLda(memory, cpu, ACTION_TARGET);
…Our readingentry requires the direct page at 0722–725if the action's flags meet the target's status bits: result 3 or 2; stop731–755run the target scripts764–766if the action was interrupted: result 3; stop767–773v = random(variance); the MP variance likewise774–781roll = random(100)782–784if roll ≥ chance: scale = 16785–789else: the hit counter + 1; defense = 0790–797scale the HP change798Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_target_action.c#L129-L217static void ShiftDamageProduct(const Lufia2Memory *memory, Lufia2CpuState *cpu) {
TransferDirectToA(cpu);
OpLda(memory, cpu, OpDp(cpu, PRODUCT + 2u));
OpRepWidths(cpu, 0x20u);
for (unsigned shift = 0u; shift < 4u; ++shift) {
OpLsrA(cpu);
const uint16_t old = OpReadM(memory, cpu, OpDp(cpu, PRODUCT));
const uint16_t value = (uint16_t)((old >> 1) | (cpu->carry ? 0x8000u : 0u));
cpu->carry = old & 1u;
Write8(memory, OpDp(cpu, PRODUCT + 1u), (uint8_t)(value >> 8));
Write8(memory, OpDp(cpu, PRODUCT), (uint8_t)value);
SetNz16(cpu, value);
…Our readingX = |change| × scale / 16; a product past 16 bits is left to the original code @129-145, 165-185P = X × v186–192if damage: X = X + P / 256 − defense / 2, at least 0 @147-159, 194-195X = X / 2196–197change = −(X − X × factor / 256)199–208if healing: change = X + P / 256209–215lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_005.s#L12249-L12400lda $7ff4d0.l ; $d1bc : $af, $d0, $f4, $7f
bit #$02.b ; $d1c0 : $89, $02
beq @br_d1cc ; $d1c2 : $f0, $08
lda #$03.b ; $d1c4 : $a9, $03
sta $0a2d.w ; $d1c6 : $8d, $2d, $0a
jmp @end_d10a.w ; $d1c9 : $4c, $0a, $d1
@br_d1cc:
lda $7ff464.l ; $d1cc : $af, $64, $f4, $7f
jsr AequRNGtimesA.l ; $d1d0 : $22, $99, $82, $80
sta $7ff464.l ; $d1d4 : $8f, $64, $f4, $7f
lda $7ff46a.l ; $d1d8 : $af, $6a, $f4, $7f
jsr AequRNGtimesA.l ; $d1dc : $22, $99, $82, $80
…Our readingif $7F:F4D0 has bit 1: result 3; end12249–12255v = random(v); the MP variance likewise12258–12263if random(100) < the chance byte ($7F:F45E): take the defense-ignoring branch12264–12267else: scale ($7F:F460) = 1612269–12272$7F:FAB7 + 1; defense ($7F:F4CC) = 0, by tdc with the direct page at 012274–12280damage: X = |change| × scale / 16; a high byte left over runs into a $00 byte12289–12321X = X + X × v / 256 − defense / 2, at least 0; X / 212324–12347change = −(X − X × factor / 256)12349–12362healing: change = X + X × v / 25612364–12397store the change12399–12400lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_000.s#L397-L430AequRNGtimesA:
phb ; $8299 : $8b
phk ; $829a : $4b
plb ; $829b : $ab
phx ; $829c : $da
phy ; $829d : $5a
php ; $829e : $08
sep #ACCU_8|IDX_8 ; $829f : $e2, $30
xba ; $82a1 : $eb
; check counter to updating RNG
ldx wCounterTilSlowlyUpdatingRNG.w ; $82a2 : $ae, $59, $05
inx ; $82a5 : $e8
…Our readingevery 55th call refreshes the random bytes408–416random(A) = (A × the next random byte) / 256, from 0 to A − 1419–425Checked by claude, 2026-11-08 — read the target-action routine in the decompilation and the disassembly, its HP scaling, and the random routineRevised after a check by a second AI model, 2026-11-08.The routine is $85:D0CD; the damage steps run from $85:D20B to $85:D2C5, and the two $00 bytes are at $85:D243 (damage) and $85:D2AB (healing). The decompilation names the chance byte HIT_CHANCE and the counter at $7F:FAB7 ACTION_HIT_COUNTER. The random routine reads one of 55 bytes and refills them every 55 calls.
Cited by: Damage formula
Each defeated enemy can drop its item: the game needs a roll from 0 to 99 below the drop's chance, which is half the high byte of the stored drop word, and then a 1 on a roll from 0 to 3, so a chance of 40 drops on about 10% of kills. It rolls for each drop entry in the enemy's list, a later success replacing an earlier one, and stops rolling once the battle has won an item, so a battle pays at most one dropped item. lufia-ii/drop-roll
About: Lufia II: Rise of the Sinistrals Item drop table
Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) ·code/bank_001.s#L18396-L18450rep #ACCU_8 ; $fb1a : $c2, $20
stz wCurrEnemyGoldGiven.w ; $fb1c : $9c, $fe, $09
lda wHitEnemyIdx.w ; $fb1f : $ad, $fa, $09
and #$00ff.w ; $fb22 : $29, $ff, $00
asl ; $fb25 : $0a
tax ; $fb26 : $aa
lda InBattleEnemyData.l, X ; $fb27 : $bf, $c0, $85, $96
clc ; $fb2b : $18
adc #$0021.w ; $fb2c : $69, $21, $00
tax ; $fb2f : $aa
sep #ACCU_8 ; $fb30 : $e2, $20
br_01_fb32:
…Our readingwalk the enemy's entries from +$21; kind 0 ends the list18396–18414for each entry of kind 3 with a nonzero word: chance = the word's high byte / 218416–18424if random(100) < chance and random(4) = 1: the result = the word's low 9 bits, flagged $20018425–18439next entry18444–18447Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_target_action.c#L677-L706OpLda(memory, cpu, ACTION_TARGET);
OpBitValue(cpu, 0x80u);
if (!cpu->zero) {
OpLda(memory, cpu, OpAbsX(cpu, 0x50u));
OpSta(memory, cpu, OpAbs(cpu, WRAM_PARTY_STAT_MEMBER_INDEX));
if (!ActionCall(memory, cpu, child, context, 0x85d6c3u, 0x81fbdbu, 3u))
return ActionUnwound(0x85d6c3u);
OpRepWidths(cpu, 0x20u);
OpLda(memory, cpu, OpAbs(cpu, WRAM_BATTLE_ACTION_BIAS));
cpu->carry = 0u;
OpAdcValue(cpu,
OpReadM(memory, cpu, OpAbs(cpu, WRAM_BATTLE_EXPERIENCE_REWARD)));
…Our readingif the fallen target is an enemy: load its experience and gold677–683add them to the battle's totals684–697if the battle has no item yet: roll the drop and keep its result698–705lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_001.s#L18522-L18541Call_01_fbdb:
phx ; $fbdb : $da
lda wHitEnemyIdx.w ; $fbdc : $ad, $fa, $09
rep #ACCU_8 ; $fbdf : $c2, $20
and #$00ff.w ; $fbe1 : $29, $ff, $00
asl ; $fbe4 : $0a
tax ; $fbe5 : $aa
lda InBattleEnemyData.l, X ; $fbe6 : $bf, $c0, $85, $96
tax ; $fbea : $aa
sep #ACCU_8 ; $fbeb : $e2, $20
lda InBattleEnemyData.l+$1d, X ; $fbed : $bf, $dd, $85, $96
sta wCurrEnemyExpGiven.w ; $fbf1 : $8d, $fc, $09
…Our readingexperience = the fallen enemy's word at +$1D; gold = its word at +$1F18524–18539Each of the 224 monsters has a record reached through a table of 224 offsets at $96:85C0: the battle loader copies its 13-letter name, four words from +$11 to +$17, and four bytes from +$19 to +$1C, which it doubles into words; the routine at $81:FBDB reads the experience and gold it pays as words at +$1D and +$1F; and a list of three-byte entries from +$21, ended by 0, holds the drop: in an entry of kind 3 the low 9 bits name the item and the top 7 bits give the chance in percent. Terror Wave names the four words HP, MP, attack, and defense, the four bytes agility, intelligence, guts, and magic resistance, and the byte at +$0D the level. 132 monsters carry a drop. HP runs up to 65535 (Egg Dragon) and experience up to 60000 (Egg Dragon). CodeChecked by claude, 2026-11-08 — read the drop roll and the reward loader in the disassembly and the defeat routine in the decompilationRevised after a check by a second AI model, 2026-11-08.The drop roll is $81:FB1A and the reward loader $81:FBDB. With the random bytes even, random(4) = 1 holds for 64 of 256 values, a quarter. The monsters table's drop column already gives the halved chance.
Cited by: Item drop table
Running from a battle has no roll in the code read: unless the battle's special-encounter flag is set, the party gets away at once. A battle loaded from the game's list of special encounters sets the flag, and there the attempt fails with a message and the battle goes on. When an enemy or the capsule monster runs, it alone leaves: it takes the status a defeated fighter gets, and the battle goes on. The routine's caller and the routines it calls aren't read, so a roll made there isn't ruled out. lufia-ii/run
About: Lufia II: Rise of the Sinistrals Fleeing
Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) ·code/bank_001.s#L6126-L6232lda $7ff44e.l ; $ab94 : $af, $4e, $f4, $7f
bmi br_01_ab9e ; $ab98 : $30, $04
cmp #$10.b ; $ab9a : $c9, $10
bne br_01_ac05 ; $ab9c : $d0, $67
br_01_ab9e:
jsr Call_01_b2b5.l ; $ab9e : $22, $b5, $b2, $81
lda $000f.w, X ; $aba2 : $bd, $0f, $00
ora #$04.b ; $aba5 : $09, $04
sta $000f.w, X ; $aba7 : $9d, $0f, $00
lda $7ff44e.l ; $abaa : $af, $4e, $f4, $7f
sta wHitEnemyIdx.w ; $abae : $8d, $fa, $09
jsr $85d9f0.l ; $abb1 : $22, $f0, $d9, $85
…Our readingif the actor is an enemy (bit 7) or the capsule monster ($10): set $04 in its status at $0F; redraw; return6126–6175if $11DD isn't 0: message $F1F0; wait; return to the battle6178–6199else: field result = 2; message $F1E7; count the run; leave the battle6202–6232Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_target_action.c#L30ACTOR_STATUS = 0x000fu,Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_target_action.c#L663-L667static Lufia2ExecutionResult DefeatTarget(const Lufia2Memory *memory,
Lufia2CpuState *cpu,
Lufia2PushedChildCall child, void *context) {
OpLoadA(cpu, 4u);
OpSta(memory, cpu, OpAbsX(cpu, ACTOR_STATUS));Our readinga defeated fighter's status = 4666–667Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_encounter_loader.c#L238-L248OpLda(memory, cpu, FIELD_BATTLE_STYLE);
OpSta(memory, cpu, OpAbs(cpu, (WRAM_BATTLE_BACKGROUND_ID & 0xffffu)));
OpLda(memory, cpu, FIELD_BATTLE_SOURCE);
if (!cpu->zero) {
OpIncA(cpu);
if (cpu->zero) {
const uint32_t unwind = LoadSpecialEncounter(memory, cpu,
child, context);
return unwind ? EncounterUnwound(unwind) :
ExecutionReturned(0x818350u);
}Our readingif the field's battle source is $FF: load a special encounter240–248Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_encounter_loader.c#L223-L224OpLoadA(cpu, 0xffu);
OpSta(memory, cpu, OpAbs(cpu, (WRAM_BATTLE_ACTION_SPECIAL_RESULT & 0xffffu)));lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_001.s#L397-L432@cont_8302:
lda $97c53d.l, X ; $8302 : $bf, $3d, $c5, $97
sta $132d.w, Y ; $8306 : $99, $2d, $13
inx ; $8309 : $e8
lda $97c53d.l, X ; $830a : $bf, $3d, $c5, $97
sta $1333.w, Y ; $830e : $99, $33, $13
tdc ; $8311 : $7b
sta $134b.w, Y ; $8312 : $99, $4b, $13
inx ; $8315 : $e8
iny ; $8316 : $c8
cpy #$0006.w ; $8317 : $c0, $06, $00
bne @cont_8302 ; $831a : $d0, $e6
…Our readingcopy the special encounter's enemies, experience, and gold from $97:C53D398–428$11DD = $FF430–431Checked by claude, 2026-11-08 — read the run action and the special-encounter loader in the disassembly and the decompilationRevised after a check by a second AI model, 2026-11-08.The run action is $81:AB94 (decompilation: battle_collective_actions.c). The world-map scene sets $11DD to 1 (world_scene.c, SaveEncounterView), which the same test would refuse; what clears it for an ordinary battle isn't read.
Taking a hit from an enemy fills a party member's IP gauge, more for a hit that takes a larger share of the HP the member had. The gain is m × g / 256 + 12, at most 255, where m = (256 − cos a) × 2, with a the hit's share of the member's HP in 256ths divided by 4 and rounded (64 is a right angle, so m runs from near 0 to 512), and g is the low byte of a word in the member's battle record times 128 / 100, at most 255 (199 instead when the word is $C800 or more). The gauge stops at 255. In the HP-change routine read, only an enemy's hit that leaves the member standing adds IP; a member who is knocked out drops to 0. lufia-ii/ip-gain
About: Lufia II: Rise of the Sinistrals Super meter
Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) ·code/bank_005.s#L12772-L12890@br_d529:
; store damage taken in 65
eor #$ffff.w ; $d529 : $49, $ff, $ff
ina ; $d52c : $1a
sta $65 ; $d52d : $85, $65
clc ; $d52f : $18
; get original hp in 58
adc todo_BattlePlayer.hp.w, X ; $d530 : $7d, $11, $00
phx ; $d533 : $da
sta $58 ; $d534 : $85, $58
stz $63 ; $d536 : $64, $63
; this will get: dmg taken (2) * 0x100 // prev hp into 63
…Our readingdamage = −change; HP before = damage + HP12774–12782r = damage × $100 / HP before12783–12786a = (r × $40 + $80) / 25612789–12802c = cos(a)12805m = ($100 − c) × 212808–12813w = the member's word at +$33; if its high byte is $C8 or more: 199, else its low byte12821–12839g = w × $80 / 100, at most $FF12842–12867gain = m × g / 256 + 12, at most $FF12868–12881IP = IP + gain, at most $FF12882–12889lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_005.s#L14074-L14092GetCosOfA:
; eg 55 = 46
php ; $de1e : $08
sep #ACCU_8|IDX_8 ; $de1f : $e2, $30
lda $54 ; $de21 : $a5, $54
clc ; $de23 : $18
adc #$40.b ; $de24 : $69, $40
sta $55 ; $de26 : $85, $55
bra _GetSinOfA ; $de28 : $80, $07
GetSinOfA:
php ; $de2a : $08
sep #ACCU_8|IDX_8 ; $de2b : $e2, $30
…Our readingcos(a) = sin(a + $40); the result runs 0 to $FF, bit 15 set if negative14074–14092Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_target_action.c#L37ACTOR_IP = 0x00bcu,Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_target_action.c#L543-L576cpu->carry = 0u;
OpAdcValue(cpu, OpReadM(memory, cpu, OpAbsX(cpu, ACTOR_HP)));
if (!cpu->carry) {
OpLda(memory, cpu, OpAbsX(cpu, ACTOR_HP));
OpLoadA(cpu, (uint16_t)(OpA(cpu) ^ (0xffffu)));
OpIncA(cpu);
} else {
OpLda(memory, cpu, HIT_POINT_CHANGE);
}
cpu->carry = 0u;
OpAdcValue(cpu, OpReadM(memory, cpu, OpAbsX(cpu, ACTOR_HP)));
OpSta(memory, cpu, OpAbsX(cpu, ACTOR_HP));
…Our readingHP = HP + change, stopping at 0543–554if HP is 0: knocked out; stop555–564if the source is an enemy, the target a party member, and the change a loss: add IP565–575Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_target_action.c#L663-L711static Lufia2ExecutionResult DefeatTarget(const Lufia2Memory *memory,
Lufia2CpuState *cpu,
Lufia2PushedChildCall child, void *context) {
OpLoadA(cpu, 4u);
OpSta(memory, cpu, OpAbsX(cpu, ACTOR_STATUS));
OpRepWidths(cpu, 0x20u);
OpStz(memory, cpu, OpAbsX(cpu, ACTOR_HP));
OpSepWidths(cpu, 0x20u);
OpLda(memory, cpu, ACTION_TARGET);
OpSta(memory, cpu, OpAbs(cpu, WRAM_PARTY_STAT_MEMBER_INDEX));
if (!ActionCall(memory, cpu, child, context, 0x85d6acu, 0x85d9f0u, 3u))
return ActionUnwound(0x85d6acu);
…Our readingthe fallen fighter's status = 4; HP = 0666–670if it is an enemy: rewards677–706else: IP = 0; its byte at +$BA + 1707–711Checked by claude, 2026-11-08 — read the IP gain and its cosine in the disassembly, and the HP change and the defeat routine in the decompilationRevised after a check by a second AI model, 2026-11-08.The IP byte is +$BC of the battle record (the decompilation's ACTOR_IP). The gain routine runs from $85:D529 to $85:D5D0; the divide is $85:DB6D and the cosine $85:DE1E. The gain is held to 255 before it is added, and the sum again. Which stat sits at +$33 isn't confirmed; the test of its high byte means a word from $0100 to $C7FF gives only its low byte. IP attacks cost up to 255 (lufia-ii-tables/ip-attacks). What the byte at +$BA counts isn't read.
The Ancient Cave has 99 floors, and the game builds each of the first 98 at random as the party reaches it; the 99th is a fixed map. Entering clears the floor count and arriving on the cave's map with a count of 0 sets it to 1; each floor is built with the count as its number and the count rises by one after it, and when the count stands at 99 the game loads the fixed map instead of building one. lufia-ii/cave-floors
code/bank_003.s#L7795-L7810cmp #$f0.b ; $b254 : $c9, $f0
bne br_03_b271 ; $b256 : $d0, $19
lda $05b4.w ; $b258 : $ad, $b4, $05
beq br_03_b271 ; $b25b : $f0, $14
lda wAncientCaveFloorPlus1.l ; $b25d : $af, $96, $e6, $7f
bne br_03_b268 ; $b261 : $d0, $05
ina ; $b263 : $1a
sta wAncientCaveFloorPlus1.l ; $b264 : $8f, $96, $e6, $7f
br_03_b268:
lda #$01.b ; $b268 : $a9, $01
tsb $05b6.w ; $b26a : $0c, $b6, $05
jsr Call_03_9e31.l ; $b26d : $22, $31, $9e, $83Our readingon map $F0 (the cave) with $05B4 nonzero, a flag neither source names: a count of 0 becomes 17795–7805then build the floor ($83:9E31)7808–7810lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_003.s#L4813-L4827lda wAncientCaveFloorPlus1.l ; $9e7d : $af, $96, $e6, $7f
cmp #$63.b ; $9e81 : $c9, $63
bne br_03_9ea2 ; $9e83 : $d0, $1d
lda #$0b.b ; $9e85 : $a9, $0b
sta $0005b0.l ; $9e87 : $8f, $b0, $05, $00
lda #$2e.b ; $9e8b : $a9, $2e
sta $0005b1.l ; $9e8d : $8f, $b1, $05, $00
lda #$40.b ; $9e91 : $a9, $40
sta $0005b2.l ; $9e93 : $8f, $b2, $05, $00
lda #$f1.b ; $9e97 : $a9, $f1
sta wCurrRoomIdx.w ; $9e99 : $8d, $ac, $05
lda #$01.b ; $9e9c : $a9, $01
…Our readingcount = 99: set the destination and load map $F1 instead, and return4813–4827lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_003.s#L4881-L4886jsr Call_03_b5d3.l ; $9f2e : $22, $d3, $b5, $83
jsr Call_03_9013.w ; $9f32 : $20, $13, $90
lda wAncientCaveFloorPlus1.l ; $9f35 : $af, $96, $e6, $7f
ina ; $9f39 : $1a
sta wAncientCaveFloorPlus1.l ; $9f3a : $8f, $96, $e6, $7f
rtl ; $9f3e : $6bOur readingbuild the floor ($83:9013), then add 1 to the count4881–4886Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/text/scene_label_callers.c#L64-L66OpLda(memory, cpu, WRAM_UNK_7FE696);
OpDecA(cpu);
OpSta(memory, cpu, OpAbs(cpu, SCENE_LABEL_NUMBER));Our readingthe floor label prints the count less 1, the floor just built64–66Archipelago: the Lufia II Ancient Cave world · worlds/lufia2ac/docs/en_Lufia II Ancient Cave.md#L11-L14whole game within a game. The Ancient Cave has 99 floors with increasingly hard enemies, red chests and blue chests. At
the end of the Ancient Cave you get to fight the Master Jelly... if you make it that far. The Master
Jelly gives you three rounds to try and kill it (or manage to vanquish your own party,
whichever one you can manage).lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_004.s#L1129-L1130tdc ; $87a9 : $7b
sta wAncientCaveFloorPlus1.l ; $87aa : $8f, $96, $e6, $7fOur readingentry: the floor count = 01129–1130Checked by claude, 2026-11-08 — read the arrival test, the floor routine's floor-99 branch and its increment in the disassembly, and the floor label in the decompilationRevised after a check by a second AI model, 2026-11-08.The count is $7F:E696 (the disassembly's wAncientCaveFloorPlus1); the floor routine is $83:9E31, called from the field setup at $83:B26D. Map $F1 is the bottom floor. Archipelago's guide names its boss the Master Jelly; no code read here settles the boss. The entry routine sets the count to 0 ($84:87AA), so every visit starts at floor 1.
No Ancient Cave floor has a seed of its own. The builder draws on the random generator the rest of the game uses, after first spending between 1 and 32 of its numbers, one more than the frame counter's low five bits. That generator is a table of 55 bytes, stirred by XOR each time its numbers run out; it is seeded at power-on and again from a byte kept in the save whenever a save is loaded. lufia-ii/cave-seed
code/bank_003.s#L4803-L4811lda $40 ; $9e6e : $a5, $40
and #$1f.b ; $9e70 : $29, $1f
ina ; $9e72 : $1a
sta $54 ; $9e73 : $85, $54
br_03_9e75:
jsr AequRNGval.l ; $9e75 : $22, $c7, $82, $80
dec $54 ; $9e79 : $c6, $54
bne br_03_9e75 ; $9e7b : $d0, $f8Our readingn = (frame counter $40 AND $1F) + 14803–4806draw n numbers from the generator and discard them4808–4811lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_000.s#L433-L455AequRNGval:
phb ; $82c7 : $8b
phk ; $82c8 : $4b
plb ; $82c9 : $ab
phx ; $82ca : $da
phy ; $82cb : $5a
php ; $82cc : $08
sep #ACCU_8|IDX_8 ; $82cd : $e2, $30
ldx wCounterTilSlowlyUpdatingRNG.w ; $82cf : $ae, $59, $05
inx ; $82d2 : $e8
cpx #$37.b ; $82d3 : $e0, $37
bcc + ; $82d5 : $90, $05
…Our readingindex = counter + 1; at 55 stir the table and restart at 0441–449answer = table byte $0521 + index450lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_000.s#L504-L520UpdateRNGvars:
ldx #$00.b ; $832d : $a2, $00
@loop_832f:
lda $0521.w, X ; $832f : $bd, $21, $05
eor $0540.w, X ; $8332 : $5d, $40, $05
sta $0521.w, X ; $8335 : $9d, $21, $05
inx ; $8338 : $e8
cpx #$18.b ; $8339 : $e0, $18
bne @loop_832f ; $833b : $d0, $f2
@loop_833d:
lda $0521.w, X ; $833d : $bd, $21, $05
eor $0509.w, X ; $8340 : $5d, $09, $05
…Our readingbytes 0-23 ^= bytes 31-54; bytes 24-54 ^= bytes 0-30506–520lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_000.s#L55-L57lda #$96.b ; $8062 : $a9, $96
sta $0558.w ; $8064 : $8d, $58, $05
jsr Call_00_82e7.l ; $8067 : $22, $e7, $82, $80Our readingpower-on: seed $96, then fill the table ($80:82E7)55–57lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_000.s#L2999-L3008Call_00_914b:
sta $54 ; $914b : $85, $54
jsr Call_00_91d3.w ; $914d : $20, $d3, $91
stx $60 ; $9150 : $86, $60
lda #$70.b ; $9152 : $a9, $70
sta $62 ; $9154 : $85, $62
ldy #$0001.w ; $9156 : $a0, $01, $00
lda [$60], Y ; $9159 : $b7, $60
sta $0558.w ; $915b : $8d, $58, $05
jsr Call_00_82e7.l ; $915e : $22, $e7, $82, $80Our readingloading a save: seed from the save's byte at offset 1, then fill the table2999–3008AncientCaveDerandomizer: a fixed-seed Ancient Cave generator for Lufia 2 · AncientCaveDerandomizer/help/derandomization.html#L6The original Lufia 2 generates Ancient Cave data on-the-fly when you change floors using a frame counter found in RAM at 7E0040 and a pile of 0x38 values at 7E0520 which get modified when performing certain actions in-game. These values determine the construction of the floor, which enemies are placed where, which items are in which chests... essentially everything about the floor.lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_000.s#L459-L503php ; $82e7 : $08
sep #ACCU_8|IDX_8 ; $82e8 : $e2, $30
lda $00 ; $82ea : $a5, $00
pha ; $82ec : $48
lda $0558.w ; $82ed : $ad, $58, $05
sta $0557.w ; $82f0 : $8d, $57, $05
ldx #$01.b ; $82f3 : $a2, $01
stx $00 ; $82f5 : $86, $00
dex ; $82f7 : $ca
ldy #$37.b ; $82f8 : $a0, $37
br_00_82fa:
txa ; $82fa : $8a
…Our readingfrom the seed at $0558, write each of the 55 bytes at $0521, stepping 21 places at a time459–491then stir the table three times493–497Checked by claude, 2026-11-08 — read the floor routine's draws, the generator, its stir and both seedings in the disassemblyRevised after a check by a second AI model, 2026-11-08.The generator is AequRNGval ($80:82C7); the disassembly calls it, or AequRNGtimesA beside it, from about 150 places, battle code among them, so every random event between saves moves the state a floor is built from. The routine at $80:914B that reseeds on load goes on to decode the save with the generator's numbers, and the save routine at $80:9184 stores a fresh random byte as the next key. The derandomizer's notes say the same in their words: the floor comes from the frame counter at $7E:0040 and the values at $7E:0520.
Each Ancient Cave floor is built rather than picked from stock maps. The builder lays out up to seven rectangular rooms, each one to four cells wide and one to four tall (the size the average of two draws), working left to right in bands down a grid 16 cells wide, and keeps a room only if it ends before column 9 and row 15 as the code counts; a room of a single cell is widened by one. Later passes, which the decompilation names for linking the floor, removing duplicate links, placing the start, the treasure room, the objects and chests, and drawing the cells, finish the floor. lufia-ii/cave-rooms
About: Lufia II: Rise of the Sinistrals Procedural dungeon
Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) ·code/bank_003.s#L2714-L2797br_03_91e7:
sep #ACCU_8 ; $91e7 : $e2, $20
lda #$83.b ; $91e9 : $a9, $83
pha ; $91eb : $48
plb ; $91ec : $ab
lda #$01.b ; $91ed : $a9, $01
sta $5a ; $91ef : $85, $5a
lda #$04.b ; $91f1 : $a9, $04
sta $5b ; $91f3 : $85, $5b
stz $56 ; $91f5 : $64, $56
stz $63 ; $91f7 : $64, $63
br_03_91f9:
…Our readingcursor at column 1, row 4; no rooms yet2719–2724row = cursor row + random(3) - 12727–2734width = mean of two random(4) + 1; keep only if width + column < 92735–2742height = mean of two random(4) + 1; keep only if height + row < 152744–2751width + height < 3: widen by one2760–2766count the room; the eighth stops the placement before it is filled2769–2774fill the rectangle ($83:9CA0)2776move right by the width; past column 8 start a new band 2 to 5 rows down, until row 152779–2796Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/cave/wram.h#L37-L38/* Room and shape grid sizes: 16 x 16 cells. */
CAVE_GRID_BYTES = 0x0100,Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/cave/wram.h#L131-L131CAVE_GRID_WIDTH = 0x10,Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/cave/ancient_cave.c#L1322-L1346Lufia2ExecutionResult Lufia2CaveBuildFloor(
const Lufia2Memory *memory,
Lufia2CpuState *cpu) {
CaveClearGrid(memory, cpu);
CaveCollectItems(memory, cpu);
CaveFirstChests(memory, cpu);
CaveChestContents(memory, cpu);
CavePlaceRooms(memory, cpu);
CaveLinkFloor(memory, cpu);
CaveDedupeLinks(memory, cpu);
CavePlaceStart(memory, cpu);
CaveTreasureRoom(memory, cpu);
…Our readingthe builder's passes in order: grid, item lists, chests, rooms, links, start, treasure room, objects, drawing1325–1345Checked by claude, 2026-11-08 — read the room placement in the disassembly and the builder's pass list and grid constants in the decompilationRevised after a check by a second AI model, 2026-11-08.The grid is $7F:EA00, 256 bytes with rows $10 apart (a cell's index is row × 16 + column, $83:9CCB), so 16 by 16, as the decompilation says. The derandomizer's ac_subr.txt calls the same array 8x15, which matches the placement bounds (column + width < 9, row + height < 15), not the array. The placement keeps a room's cells in columns 1 to 7 and rows 3 to 13; the merge and linking passes after it fill cells beyond those bounds (the linking pass gives an empty cell beside a room that room's number, $83:9281 on), and lufia-ii/cave-layout-measured saw cells in columns 1 to 8 and rows 2 to 14. The random helpers are $83:9E1B (a byte times n, high byte) and $83:9DE4 (the mean of two).
Measured by calling the cartridge's own floor builder in Mesen 30 times for each floor from 1 to 98 (2,940 floors, the generator's state running on from one build to the next, from a state the probe sets rather than a save): every cell a floor used lay in columns 1 to 8 and rows 2 to 14 of the 16-by-16 grid, no floor had more than 7 rooms, 20 enemies, or 8 chests, and every enemy placed was one of the six its floor's entries in the enemy table allow. lufia-ii/cave-layout-measured
About: Lufia II: Rise of the Sinistrals Procedural dungeon
Value
{
"probe": {
"builds": 2940,
"columns": [
1,
8
],
"rows": [
2,
14
],
"rooms": 7,
"enemies": 20,
"chests": 8,
"offTable": 0
}
}0x19013-0x19E30 — $83:9013-$83:9E30, the builder and the routines it calls in bank $83, run by the probeChecked by claude, 2026-11-08 — ran probes/lufia-ii/cave-builder.mjs: it halts the game after 300 frames from power-on, calls $83:9013 with the floor count set, stops at $83:95A0 (after objects and chests, before drawing), reads the grid, chests and enemies, and calls it againChecked by a second AI model, 2026-11-08.Probe: probes/lufia-ii/cave-builder.mjsMesenCE 2.2.1 (build 4b8a196), Lufia II - Rise of the Sinistrals (USA). The probe calls the builder directly, so the floor routine's 1 to 32 discarded draws and the drawing passes don't run; the passes measured read only the floor count, the ROM's tables and the generator. The probe stops each build before the tiles are drawn. The rules measured are lufia-ii/cave-rooms and lufia-ii/cave-enemies, and the table lufia-ii-tables/cave-enemies.
Which enemies an Ancient Cave floor can hold depends only on its number: each enemy placed on floor N is entry 2(N − 1) plus a random 0 to 5 of a 200-entry table, so each floor has six kinds, a floor shares four of them with the next, and each entry serves three floors. A floor makes 4 to 7 tries to place an enemy, each at a random spot of a random cell, and a try fails when no cell is found or the spot is beside the start or another object; a treasure room adds up to 13 more, and a floor holds at most 20. lufia-ii/cave-enemies
About: Lufia II: Rise of the Sinistrals Visible encounter
CodeLufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) ·src/cave/cave_objects.c#L95-L136static uint32_t Lufia2CaveAddObjectBody(const Lufia2Memory *memory,
Lufia2CpuState *cpu) {
OpPushX(memory, cpu); /* 9A1C */
OpLdx(cpu, OpReadX(memory, cpu, OpAbs(cpu, CAVE_OBJECT_COUNT)));
OpCpx(cpu, 0x0014u);
if (!cpu->carry) {
OpLda(memory, cpu, OpDp(cpu, CAVE_DP_TILE_COLUMN));
OpSta(memory, cpu, OpAbsX(cpu, CAVE_OBJECT_COLUMNS));
OpLda(memory, cpu, OpDp(cpu, CAVE_DP_TILE_ROW));
OpSta(memory, cpu, OpAbsX(cpu, CAVE_OBJECT_ROWS));
OpTxy(cpu);
OpLda(memory, cpu, OpAbs(cpu, CAVE_FLOOR)); /* 9A30 */
…Our readingat 20 objects, add none99–100keep the spot's column and row101–104index = (floor - 1) × 2 + random(6); monster = table $94:D95C[index], kept at $7F:F966 + slot106–117the monster's sprite gives the object's size118–131Lufia II - Rise of the Sinistrals (USA) · 0x19A37-0x19A41 — $83:9A37, the random(6) call and the add (A9 06 20 1B 9E 18 65 54 E2 30 AA), which the disassembly decodes with a 16-bit accumulator as lda #$2006.w and mvnlufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_003.s#L4029-L4068Call_03_9a1c:
phx ; $9a1c : $da
ldx $e731.w ; $9a1d : $ae, $31, $e7
cpx #$0014.w ; $9a20 : $e0, $14, $00
bcs br_03_9a69 ; $9a23 : $b0, $44
lda $8f ; $9a25 : $a5, $8f
sta $e6b1.w, X ; $9a27 : $9d, $b1, $e6
lda $91 ; $9a2a : $a5, $91
sta $e6d1.w, X ; $9a2c : $9d, $d1, $e6
txy ; $9a2f : $9b
lda $e696.w ; $9a30 : $ad, $96, $e6
dea ; $9a33 : $3a
…Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/cave/ancient_cave.c#L717-L755static void CaveObjectsAndChests(
const Lufia2Memory *memory, Lufia2CpuState *cpu) {
LoadA8(cpu, CAVE_EXTRA_ROOM_OBJECTS); /* 9515 */
Lufia2CaveRandomBelow(memory, cpu, 0x9517u);
cpu->carry = 0;
OpAdcValue(cpu, CAVE_MIN_ROOM_OBJECTS);
OpSta(memory, cpu, OpDp(cpu, CAVE_DP_OBJECT_TARGET));
OpStz(memory, cpu, OpDp(cpu, CAVE_DP_OBJECT_TARGET + 1u));
OpLdx(cpu, 0x0000u);
do {
LoadA8(cpu, CAVE_OBJECT_JITTER); /* 9524 */
Lufia2CaveRandomBelow(memory, cpu, 0x9526u);
…Our readingtarget = random(4) + 4 placement tries720–724each: a random cell, a spot within it; skip near the start or a placed object, else add726–754Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/cave/ancient_cave.c#L652-L697static void CaveTreasureRoom(const Lufia2Memory *memory, Lufia2CpuState *cpu) {
CaveRandomByte(memory, cpu, 0x949du); /* 949D */
OpCmpValue(cpu, CAVE_TREASURE_ROOM_ODDS);
if (cpu->carry)
return;
LoadA8(cpu, CAVE_TREASURE_MARK);
OpSta(memory, cpu, OpDp(cpu, CAVE_DP_SCRATCH_COUNT + 1u));
OpLdy(cpu, CAVE_FIRST_ROOM_CELL);
for (;;) {
OpLda(memory, cpu, OpAbsY(cpu, CAVE_ROOM_GRID)); /* 94AC */
if (!cpu->zero &&
(OpCmp(memory, cpu, OpAbsY(cpu, CAVE_ROOM_GRID + CAVE_CELL_RIGHT)),
…Our reading1 floor in 16 (a byte below $10): look for a 2 × 2 block of one room, each taken with odds 128 in 256653–66813 tries at random spots in it, each added unless near the start or an object676–697The Ancient Cave's enemies by floor: an enemy on floor N is one of the six entries from 2(N − 1) of a 200-byte table of monster numbers at $94:D95C, which names 149 different monsters in all. Floor 1 holds Goblin, Goblin Mage, Armor goblin, Regal Goblin, Troll, Ork; floor 98 Dark Warrior, Ochi Warrior, Sly Fox, Pierre. CodeChecked by claude, 2026-11-08 — read the object routine and both placement passes in the decompilation, checked the misdecoded bytes in the ROM, and compared the disassembly's linesRevised after a check by a second AI model, 2026-11-08.The table is $94:D95C (file 0xA595C), the derandomizer's enemy table; Archipelago's options describe the vanilla game the same way, 'Ninja, e.g., is allowed to appear on the 3 floors B44-B46'. The objects placed here are the field enemies the encounter claim (lufia-ii/field-encounter-slots) reads back from $7F:F966.
Cited by: Level scaling, Visible encounter
An Ancient Cave floor has at most eight chests. The builder scans the grid for 2-by-2 blocks of cells in one room and tries a chest in each block, marking it used, until eight are placed or the grid scan ends; one floor in 16 can also get a treasure room, a 2-by-2 block that takes up to eight chest tries of its own and a cluster of up to 13 enemies. lufia-ii/cave-chest-places
src/cave/ancient_cave.c#L756-L790OpLdx(cpu, CAVE_FIRST_ROOM_CELL); /* 955A */
do {
OpLda(memory, cpu, OpAbsX(cpu, CAVE_ROOM_GRID)); /* 955D */
if (!cpu->zero && !cpu->negative &&
(OpCmp(memory, cpu, OpAbsX(cpu, CAVE_ROOM_GRID + CAVE_CELL_RIGHT)),
cpu->zero) &&
(OpCmp(memory, cpu, OpAbsX(cpu, CAVE_ROOM_GRID + CAVE_CELL_DOWN)),
cpu->zero) &&
(OpCmp(memory, cpu, OpAbsX(cpu, CAVE_ROOM_GRID + CAVE_CELL_DOWN_RIGHT)),
cpu->zero)) {
OpOraValue(cpu, CAVE_CELL_MARKED); /* 9573 */
OpSta(memory, cpu, OpAbsX(cpu, CAVE_ROOM_GRID));
…Our readingeach cell from $10 to $EF: a room cell, not marked, with the same room to the right, below and below right756–765mark the four cells and try a chest766–772carry clear (placed): stop at 8 chests773–785Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/cave/ancient_cave.c#L698-L713OpLdx(cpu, CAVE_TREASURE_CHESTS); /* 94FC */
do {
OpPushX(memory, cpu);
OpLda(memory, cpu, OpAbs(cpu, CAVE_TREASURE_CELL));
Lufia2CaveAddChest(memory, cpu, 0x9503u);
OpPullX(memory, cpu);
OpDex(cpu);
} while (!cpu->zero);
break;
}
OpIny(cpu); /* 950C */
OpCpy(cpu, CAVE_TREASURE_LAST_CELL);
…Our readingthe treasure room: eight chest tries at its cell698–705Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/cave/wram.h#L143-L157/* Treasure room, objects and chests of ordinary rooms. */
CAVE_TREASURE_ROOM_ODDS = 0x10,
CAVE_TREASURE_CELL_ODDS = 0x80,
CAVE_TREASURE_LAST_CELL = 0xc0,
CAVE_TREASURE_CELL = 0xe6a8,
CAVE_TREASURE_MARK = 0xea,
CAVE_TREASURE_OBJECTS = 13,
CAVE_TREASURE_CHESTS = 8,
CAVE_TREASURE_SPREAD = 8,
CAVE_TREASURE_COLUMN_OFFSET = 1,
CAVE_TREASURE_ROW_OFFSET = 3,
CAVE_MIN_ROOM_OBJECTS = 4,
…lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_003.s#L4171-L4184br_03_9b01:
jsr Call_03_9a6b.w ; $9b01 : $20, $6b, $9a
bcs br_03_9b17 ; $9b04 : $b0, $11
ldy $e734.w ; $9b06 : $ac, $34, $e7
lda $8f ; $9b09 : $a5, $8f
sta $e736.w, Y ; $9b0b : $99, $36, $e7
lda $91 ; $9b0e : $a5, $91
sta $e73e.w, Y ; $9b10 : $99, $3e, $e7
inc $e734.w ; $9b13 : $ee, $34, $e7
clc ; $9b16 : $18
br_03_9b17:
rts ; $9b17 : $60Our readingthe try's test ($83:9A6B) fails: carry set, no chest4171–4173else store the chest's position, count it at $E734, and clear carry4175–4181Checked by claude, 2026-11-08 — read both chest passes and their constants in the decompilationRevised after a check by a second AI model, 2026-11-08.Chests are $83:9ABC; it returns carry clear when it places a chest (inc $e734; clc) and carry set when the try is rejected, so the second counter the loop tests also counts placed chests and the chest count ends it first, as the decompilation's comment says. The treasure room is placed only where its 2-by-2 search finds a block. Which word a chest takes is in lufia-ii/cave-chest-contents.
Each Ancient Cave floor rolls the contents of its chests before it lays out its rooms: eight rolls of a byte from 0 to 255, one per chest. A roll of 174 or more gives a weapon, 129 to 173 a piece of armour, 99 to 128 a spell scroll for a spell none of the four party members knows (or else a restorative), 94 to 98 a blue chest, 36 to 93 a restorative, and 0 to 35 another consumable. Weapons, spells, blue chests and the other consumables are drawn evenly from their lists, and armour evenly from the first n mod 128 items of its list of n (lufia-ii/cave-armor-wrap); the restorative takes the average of two draws, so the middle of its list of nine comes up most. When an Iris treasure or Providence takes the first chest, the rolls fill the other seven. lufia-ii/cave-chest-contents
code/bank_003.s#L2620-L2711br_03_9142:
jsr AequRNGval.l ; $9142 : $22, $c7, $82, $80
cmp #$ae.b ; $9146 : $c9, $ae
bcs br_03_916f ; $9148 : $b0, $25
cmp #$81.b ; $914a : $c9, $81
bcs br_03_9176 ; $914c : $b0, $28
cmp #$63.b ; $914e : $c9, $63
bcs br_03_9192 ; $9150 : $b0, $40
cmp #$5e.b ; $9152 : $c9, $5e
bcs br_03_91c8 ; $9154 : $b0, $72
cmp #$24.b ; $9156 : $c9, $24
bcs br_03_91ad ; $9158 : $b0, $53
…Our readingroll a byte; 174+ weapon list, 129+ armour list, 99+ spell, 94+ blue table, 36+ restorative, else the consumable table2621–2635below 36: one of 31 from $94:F13D2637–2643weapon or armour: one of the list, from its length's low byte halved2645–2666spell: one of 35; known to the party ($83:C652): the restorative instead; else the spell, high byte $802668–2681restorative: the mean of two draws below 9 from $91:FFDC2683–2695blue: one of 41 from $94:EEA0, high byte ORed with $402697–2704eight words in all2706–2711Archipelago: the Lufia II Ancient Cave world · worlds/lufia2ac/Options.py#L104-L105# blue chest = 5/256, spell = 30/256, gear = 45/256 (and the remaining part, weapon = 82/256)
chest_type_chances: List[float] = [36 * ratio, 58 * ratio, float(self.value), 30 * ratio, 45 * ratio]The Ancient Cave's four fixed chest lists, as item words in the ROM: the nine Iris treasures at $91:FFCA, the nine restoratives at $91:FFDC (Potion and Hi-Magic twice each), the 41 blue-chest items at $94:EEA0, which are also the items the cave lets the party keep, and the 31 other consumables at $94:F13D. Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_003.s#L10714-L10767Call_03_c652:
phb ; $c652 : $8b
sta $54 ; $c653 : $85, $54
lda #$00.b ; $c655 : $a9, $00
pha ; $c657 : $48
plb ; $c658 : $ab
ldy #$00.b ; $c659 : $a0, $00
.db $00 ; $c65b : $00
br_03_c65c:
phy ; $c65c : $5a
tdc ; $c65d : $7b
lda wPartyCharTypeIdxes.w, Y ; $c65e : $b9, $7b, $0a
…Our readingeach of the four party slots with a member: compare the spell with the 36 bytes at its record + $9610715–10756no match: carry clear; a match: carry set, so the chest takes a restorative ($83:919F, bcs)10758–10767From floor 10 on, Ancient Cave armour chests give only body armour. The chest pick halves the low byte of the list's length in bytes, so a list of more than 127 items is drawn from only its first n − 128: the armour list reaches 129 items at floor 10, where every armour chest holds its first item, an Apron, and from floor 60 it holds 185 and draws from the first 57, all body armour, which comes first in item order. Shields, helmets, rings and jewels come out of armour chests only on floors 1 to 9; the weapon list never passes 88 items and is drawn whole. CodeChecked by claude, 2026-11-08 — read the chest loop whole in the disassembly and decoded its tables from the ROMRevised after a check by a second AI model, 2026-11-08.The shares are 82, 45, 30, 5, 58 and 36 in 256, as Archipelago's options list them. The derandomizer's help labels the 9-item table 'non-restorative' and the 31-item one 'restorative'; the ROM's lists are the other way round (Potion, Hi-Magic, Miracle in the nine; balls, boomerangs and gourds in the 31), which is how Archipelago describes them. The chest words are $7F:E746; an Iris or Providence word is written first by $83:90C5 (lufia-ii/cave-iris, lufia-ii/cave-providence).
Weapon and armour chests deepen with the floor: the builder lists, for each floor, every item marked as found in the field and not marked as excluded whose price is under (floor + 1) × 1,000 gold, or any price from floor 60 on, in item order; items of type 1 go on the weapon list and the rest on the armour list. lufia-ii/cave-item-pools
code/bank_003.s#L2478-L2555ldx #$0000.w ; $903e : $a2, $00, $00
stx $5d ; $9041 : $86, $5d
ldx #$1000.w ; $9043 : $a2, $00, $10
stx $60 ; $9046 : $86, $60
lda wAncientCaveFloorPlus1.l ; $9048 : $af, $96, $e6, $7f
cmp #$3c.b ; $904c : $c9, $3c
bcc br_03_9058 ; $904e : $90, $08
lda #$ff.b ; $9050 : $a9, $ff
sta $54 ; $9052 : $85, $54
sta $55 ; $9054 : $85, $55
bra br_03_9074 ; $9056 : $80, $1c
br_03_9058:
…Our readingboth lists empty: weapons from $7F:0000, armour from $7F:10002478–2481floor 60 or more: no price limit; else the limit is 1000 × (floor + 1)2482–2502each of 466 items: byte 0 bit 1 set, byte 0 bit 5 clear, byte 1 bit 5 clear2507–2521price (bytes 5-6) under the limit2523–2526byte 7 bit 0 set: the weapon list, else the armour list2528–2548AncientCaveDerandomizer: a fixed-seed Ancient Cave generator for Lufia 2 · AncientCaveDerandomizer/help/distribution.html#L16-L22Item data relevant to Ancient Cave inclusion can be found at 0xB4F69 in the ROM, which is a table of 0x1D2 16-bit offsets pointing ahead to variable-sized blocks of data for each of the 0x1D2 items. The data relevant to Ancient Cave includes:
<ul>
<li>Byte 0, bit 0x02 must be "on" for Ancient Cave inclusion. The Derandomizer modifies this value to include or exclude items.</li>
<li>Byte 0, bit 0x20 must be "off" for Ancient Cave inclusion. The Derandomizer modifies this value to include or exclude items.</li>
<li>Byte 1, bit 0x20 must be "off" for Ancient Cave inclusion. The Derandomizer modifies this value to include or exclude items.</li>
<li>Bytes 5 and 6, forming a 16-bit item "gold value," are used to determine which items will come up on which floors. An item's value must be less than (the current floor number + 1) * 1000 for it to show up on any given floor. The Derandomizer modifies this value to make items show up sooner or later depending on the chosen settings.</li>
<li>Byte 7 indicates the item type. The only relevant values here are whether this is 0x01 (indicating a weapon) or greater (indicating an armor). Consumables are indicated by 00, but that value is not used here since consumables are handled differently.</li>The Ancient Cave's weapon and armour lists by floor, as the builder makes them from the item records: the price ceiling, how many items each list holds, and how many the chest pick can reach, which is the count modulo 128. From floor 60 the ceiling is gone and the lists stay at 88 weapons and 185 armour pieces, of which 57 can be drawn; the armour list first passes 127 items on floor 10. CodeChecked by claude, 2026-11-08 — read the list builder in the disassembly and decoded the lists for every floor from the ROM's item recordsChecked by a second AI model, 2026-11-08.The derandomizer names the fields (bit 1 for inclusion, type 1 for weapons) and the price rule; the code agrees. Each list's end offset is kept as a word, but the chest pick reads only its low byte (lufia-ii/cave-armor-wrap).
From floor 10 on, Ancient Cave armour chests give only body armour. The chest pick halves the low byte of the list's length in bytes, so a list of more than 127 items is drawn from only its first n − 128: the armour list reaches 129 items at floor 10, where every armour chest holds its first item, an Apron, and from floor 60 it holds 185 and draws from the first 57, all body armour, which comes first in item order. Shields, helmets, rings and jewels come out of armour chests only on floors 1 to 9; the weapon list never passes 88 items and is drawn whole. lufia-ii/cave-armor-wrap
code/bank_003.s#L2645-L2666br_03_916f:
ldx #$0000.w ; $916f : $a2, $00, $00
lda $5d ; $9172 : $a5, $5d
bra br_03_917b ; $9174 : $80, $05
br_03_9176:
ldx #$1000.w ; $9176 : $a2, $00, $10
lda $60 ; $9179 : $a5, $60
br_03_917b:
stx $54 ; $917b : $86, $54
lsr ; $917d : $4a
jsr Call_03_9e11.w ; $917e : $20, $11, $9e
rep #ACCU_8 ; $9181 : $c2, $20
…Our readingweapons: base $0000, A = the low byte at $5D; armour: base $1000, A = the low byte at $602645–2652count = A / 2; index = random below count, doubled2655–2657word = list[base + index]2658–2664lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_003.s#L4770-L4777Call_03_9e1b:
sta $00211c.l ; $9e1b : $8f, $1c, $21, $00
jsr AequRNGval.l ; $9e1f : $22, $c7, $82, $80
sta $00211b.l ; $9e23 : $8f, $1b, $21, $00
tdc ; $9e27 : $7b
sta $00211b.l ; $9e28 : $8f, $1b, $21, $00
lda $002135.l ; $9e2c : $af, $35, $21, $00
rts ; $9e30 : $60Our readingrandom below n = the high byte of a random byte times n4771–4776The Ancient Cave's weapon and armour lists by floor, as the builder makes them from the item records: the price ceiling, how many items each list holds, and how many the chest pick can reach, which is the count modulo 128. From floor 60 the ceiling is gone and the lists stay at 88 weapons and 185 armour pieces, of which 57 can be drawn; the armour list first passes 127 items on floor 10. CodeMeasured in the same 2,940 builds of floors 1 to 98 in Mesen (lufia-ii/cave-layout-measured): every armour roll gave an item from the first n − 128 of its floor's list once the list passed 127 items, and every one on floor 10 was an Apron; Providence first appeared on floor 21 and took the first chest of every floor-60-and-deeper build that no Iris treasure took; and with no new visit between builds, each of the nine Iris treasures appeared exactly once. VerifiedChecked by claude, 2026-11-08 — read the pick in the disassembly (A is 8 bits there: the compares before it take one-byte operands) and counted the lists from the ROM's item recordsChecked by a second AI model, 2026-11-08.The end offsets are words ($5D for weapons from 0, $60 for armour from $1000), written 16 bits wide at $83:90A2-$83:90BA. A list of 128 items gives a count of 0, and random below 0 is 0, so that floor too gives only the list's first item. No source read here mentions the wrap. lufia-ii-tables/cave-item-pools gives each floor's listed and drawn counts.
Measured in the same 2,940 builds of floors 1 to 98 in Mesen (lufia-ii/cave-layout-measured): every armour roll gave an item from the first n − 128 of its floor's list once the list passed 127 items, and every one on floor 10 was an Apron; Providence first appeared on floor 21 and took the first chest of every floor-60-and-deeper build that no Iris treasure took; and with no new visit between builds, each of the nine Iris treasures appeared exactly once. lufia-ii/cave-chest-measured
Value
{
"probe": {
"armorRolls": 3735,
"outsideDrawn": 0,
"floor10": [
"Apron"
],
"providenceFrom": 21,
"everyBuildFrom60": true,
"irisEach": 1
}
}0x19013-0x19E30 — $83:9013-$83:9E30, the builder and the routines it calls in bank $83, run by the probeChecked by claude, 2026-11-08 — ran probes/lufia-ii/cave-builder.mjs, which classifies each chest word by the floor's lists as the probe decodes them from the ROMChecked by a second AI model, 2026-11-08.Probe: probes/lufia-ii/cave-builder.mjsMesenCE 2.2.1 (build 4b8a196). The Iris bits at $7F:E75E are cleared only on entering the cave, which the probe never does, so each treasure was offered once in the whole run; the event flags 200 to 208 were clear throughout. The rules measured are lufia-ii/cave-armor-wrap, lufia-ii/cave-providence and lufia-ii/cave-iris.
On each floor the Ancient Cave builds, there is a 5-in-256 chance that the game picks one of the nine Iris treasures at random for the floor's first chest. The treasure goes in only if it hasn't been picked before in this visit and the player hasn't already earned it: one bit per treasure, cleared on entry, marks it picked even when the chest isn't placed, and its event flag, set when the party leaves with it, marks it earned. No floor number is tested. lufia-ii/cave-iris
code/bank_003.s#L2557-L2594lda #$7f.b ; $90c5 : $a9, $7f
pha ; $90c7 : $48
plb ; $90c8 : $ab
ldy #$0000.w ; $90c9 : $a0, $00, $00
tdc ; $90cc : $7b
sta $e75d.w ; $90cd : $8d, $5d, $e7
jsr AequRNGval.l ; $90d0 : $22, $c7, $82, $80
cmp #$05.b ; $90d4 : $c9, $05
bcs br_03_9116 ; $90d6 : $b0, $3e
lda #$09.b ; $90d8 : $a9, $09
jsr Call_03_9e1b.w ; $90da : $20, $1b, $9e
sta $58 ; $90dd : $85, $58
…Our readinga random byte of 5 or more: no Iris chest2563–2565kind = random below 92567–2569its bit at $7F:E75E already set: no Iris chest; else set it2570–2576event flag 200 + kind set: no Iris chest2577–2581first chest = the kind's item from $91:FFCA, ORed with $02002583–2590lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_004.s#L1129-L1135tdc ; $87a9 : $7b
sta wAncientCaveFloorPlus1.l ; $87aa : $8f, $96, $e6, $7f
sta $7fe759.l ; $87ae : $8f, $59, $e7, $7f
sta $7fe75b.l ; $87b2 : $8f, $5b, $e7, $7f
sta $7fe75d.l ; $87b6 : $8f, $5d, $e7, $7f
sta $7fe75e.l ; $87ba : $8f, $5e, $e7, $7f
sta $7fe75f.l ; $87be : $8f, $5f, $e7, $7fOur readingentry zeroes the count and $7F:E759, $7F:E75B, $7F:E75D, $7F:E75E and $7F:E75F, the Iris bits among them1129–1135The Ancient Cave's four fixed chest lists, as item words in the ROM: the nine Iris treasures at $91:FFCA, the nine restoratives at $91:FFDC (Potion and Hi-Magic twice each), the 41 blue-chest items at $94:EEA0, which are also the items the cave lets the party keep, and the 31 other consumables at $94:F13D. CodeChecked by claude, 2026-11-08 — read the first-chest routine and the entry's clears in the disassembly and decoded the treasure table from the ROMRevised after a check by a second AI model, 2026-11-08.The flags are set by the exit (lufia-ii/cave-exit). TCRF's notes number flags 200 to 209 as treasures 1 to 10, with 202 also called the boss's flag; the code reads flags 200 to 208 for the nine items. Archipelago lists the nine Iris items (worlds/lufia2ac/Items.py#L455-L463).
From floor 21 on, an Ancient Cave floor's first chest can hold Providence (item $2D): the chance is about the floor number in 60, so certain from floor 60, unless an Iris treasure took the chest. Once a chest holding Providence has been opened, no more are placed in that visit. lufia-ii/cave-providence
code/bank_003.s#L2596-L2618br_03_9116:
lda $7fe75b.l ; $9116 : $af, $5b, $e7, $7f
bmi br_03_9142 ; $911a : $30, $26
tdc ; $911c : $7b
sta $7fe75b.l ; $911d : $8f, $5b, $e7, $7f
lda wAncientCaveFloorPlus1.l ; $9121 : $af, $96, $e6, $7f
cmp #$15.b ; $9125 : $c9, $15
bcc br_03_9142 ; $9127 : $90, $19
lda #$3c.b ; $9129 : $a9, $3c
jsr Call_03_9e1b.w ; $912b : $20, $1b, $9e
cmp wAncientCaveFloorPlus1.l ; $912e : $cf, $96, $e6, $7f
bcs br_03_9142 ; $9132 : $b0, $0e
…Our reading$7F:E75B negative (Providence opened): none2596–2597floor below 21: none2599–2603random below 60 not under the floor number: none2605–2608first chest = $022D (item $2D, Providence)2610–2613Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/field/field_object_rewards.c#L135-L150OpLda(memory, cpu, OpAbs(cpu, REWARD_REMAINING + 1u));
OpAndValue(cpu, 0x7fu);
OpOraValue(cpu, OpReadM(memory, cpu, OpAbs(cpu, REWARD_REMAINING)));
if (cpu->zero) {
TransferDirectToA(cpu);
OpLda(memory, cpu, REWARD_OBJECT);
OpAslA(cpu);
OpTax(cpu);
OpRepWidths(cpu, 0x20u);
OpLda(memory, cpu, OpLongX(cpu, REWARD_VALUES));
OpAndValue(cpu, 0x1ffu);
OpCmpValue(cpu, 0x2du);
…Our readinga chest's item word, low 9 bits $2D: $7F:E75B = $FFFF143–150Measured in the same 2,940 builds of floors 1 to 98 in Mesen (lufia-ii/cave-layout-measured): every armour roll gave an item from the first n − 128 of its floor's list once the list passed 127 items, and every one on floor 10 was an Apron; Providence first appeared on floor 21 and took the first chest of every floor-60-and-deeper build that no Iris treasure took; and with no new visit between builds, each of the nine Iris treasures appeared exactly once. VerifiedChecked by claude, 2026-11-08 — read the Providence branch in the disassembly and the chest reward in the decompilationRevised after a check by a second AI model, 2026-11-08.Item $2D is named Providence in the ROM's name table. The official guidebook (p. 72, OCR) says the item is found from floor 20; the code's test is the floor count, which equals the floor's number during the build, against 21. Random below 60 is the high byte of a byte times 60, so floor n gives a chance of about n/60.
Entering the Ancient Cave takes everything from the party except its blue-chest items. The game moves each item on the blue list from the bag and from the four party members' equipment to a list of its own, saves a copy of the party, then clears all but the first 14 bytes of each of the seven members' records, the bag, the gold and the play time, puts 10 Potions in the bag, gives back the blue items, and rebuilds the seven members from their default records; when the byte at $0A7F, which neither source names, is 7, it also returns every capsule monster to level 1, a step no probe has covered. lufia-ii/cave-entry
About: Lufia II: Rise of the Sinistrals Metaprogression
Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) ·code/bank_004.s#L1136-L1201ldy #$0000.w ; $87c2 : $a0, $00, $00
sty $60 ; $87c5 : $84, $60
rep #ACCU_8 ; $87c7 : $c2, $20
br_04_87c9:
lda wInventoryItemsAndCounts.w, Y ; $87c9 : $b9, $8d, $0a
jsr Call_04_886d.w ; $87cc : $20, $6d, $88
bcc br_04_87db ; $87cf : $90, $0a
lda wInventoryItemsAndCounts.w, Y ; $87d1 : $b9, $8d, $0a
jsr Call_04_8862.w ; $87d4 : $20, $62, $88
tdc ; $87d7 : $7b
sta wInventoryItemsAndCounts.w, Y ; $87d8 : $99, $8d, $0a
br_04_87db:
…Our readingeach of the 96 bag slots: on the blue list: append it to $7F:BF00, empty the slot1136–1154each of the four party slots with a member: each of six equipment words at its record + $66, the same, marked $02001156–1198end the list with a 0 word1200–1201lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_004.s#L1205-L1235br_04_882f:
rep #ACCU_8 ; $882f : $c2, $20
lda $8b20.w, X ; $8831 : $bd, $20, $8b
cmp #$ffff.w ; $8834 : $c9, $ff, $ff
beq br_04_885b ; $8837 : $f0, $22
sta $5d ; $8839 : $85, $5d
lda $8b23.w, X ; $883b : $bd, $23, $8b
sta $58 ; $883e : $85, $58
sep #ACCU_8 ; $8840 : $e2, $20
lda $8b22.w, X ; $8842 : $bd, $22, $8b
sta $5f ; $8845 : $85, $5f
ldy #$0000.w ; $8847 : $a0, $00, $00
…Our readingcopy each range of the table at $84:8B20 to $7F:B000, then reset ($84:8888)1205–1235lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_004.s#L1274-L1347Call_04_8888:
phb ; $8888 : $8b
phk ; $8889 : $4b
plb ; $888a : $ab
ldx #$0000.w ; $888b : $a2, $00, $00
br_04_888e:
rep #ACCU_8 ; $888e : $c2, $20
lda $8b59.w, X ; $8890 : $bd, $59, $8b
cmp #$ffff.w ; $8893 : $c9, $ff, $ff
beq br_04_88bb ; $8896 : $f0, $23
sta WMADDL.w ; $8898 : $8d, $81, $21
lda $8b5c.w, X ; $889b : $bd, $5c, $8b
…Our readingzero each range of the table at $84:8B591280–1306first bag slot = $1402: item 2 (Potion), 10 of it1309–1310a normal entry ($7F:E759 = 0): give each saved item back ($82:E746)1312–1340rebuild the members ($81:ED35) and the capsule monsters ($82:C2FD)1344–1345Lufia II - Rise of the Sinistrals (USA) · 0x20B20-0x20B9B — $84:8B20 (the saved ranges) and $84:8B59 (the cleared ranges), five bytes each: address, bank, lengthLufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/system/default_records.c#L162-L176Lufia2ExecutionResult Lufia2PartyResetDefaultRecords(
const Lufia2Memory *memory, Lufia2CpuState *cpu,
Lufia2PushedChildCall child, void *context) {
if (!child || !cpu->accumulator_is_8_bit || cpu->index_is_8_bit || cpu->decimal)
return ExecutionHandoff(cpu, 0x81ed35u);
PushDataBank(memory, cpu);
OpSetDataBank(memory, cpu, DEFAULT_RECORD_DATA_BANK);
SetDefaultRecordPointers(memory, cpu);
OpLdx(cpu, 0xb395u);
OpStz(memory, cpu, OpAbs(cpu, WRAM_PARTY_STAT_MEMBER_INDEX));
const uint32_t unpack_sites[] = {
0x81ed55u, 0x81ed5bu, 0x81ed61u, 0x81ed67u,
…Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/party/capsule.c#L481-L488/* $82:C2FD: every capsule back to level 1, then stats. */
Lufia2ExecutionResult Lufia2CapsuleReset(
const Lufia2Memory *memory,
Lufia2CpuState *cpu) {
LoadAAbsolute8(memory, cpu, 0x0a7fu, 0);
Compare8(cpu, A8(cpu), 0x07u);
if (!cpu->zero)
return ExecutionReturned(0x82c351u);Our readingthe capsule reset returns at once unless $0A7F is 7485–488Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/cave/cave_entry.c#L21-L41static void TestBlueItemBody(const Lufia2Memory *memory, Lufia2CpuState *cpu) {
OpAndValue(cpu, 0x01ffu);
OpSta(memory, cpu, OpDp(cpu, DP_BLUE_ITEM));
OpLdx(cpu, 0u);
for (;;) {
OpLda(memory, cpu, OpLongX(cpu, ROM_BLUE_ITEMS));
OpCmp(memory, cpu, OpDp(cpu, DP_BLUE_ITEM));
if (cpu->zero) {
cpu->carry = 1u;
break;
}
OpInx(cpu);
…Our readingthe blue test: the item's low 9 bits against each of the 41 words at $94:EEA023–40lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_002.s#L10098-L10100lda $0a7f.w ; $c2fd : $ad, $7f, $0a
cmp #$07.b ; $c300 : $c9, $07
bne br_02_c351 ; $c302 : $d0, $4dOur reading$0A7F not 7: skip the capsule reset ($82:C351)10098–10100Checked by claude, 2026-11-08 — read the entry, its blue-item test and the reset in the disassembly and decompilation, and decoded both range tables from the ROMRevised after a check by a second AI model, 2026-11-08.Checked by a second AI model, 2026-11-08.The entry is $84:878A. The saved ranges are the seven member records ($0BAD, $532 bytes), the bag ($0A8D, $C0), the gold ($0A8A, 3), $119D-$11D7 (capsule monster state, by the decompilation's names), play time and counters ($0B4D, 5; $0B59, $F), $091E (8) and four blocks in bank $7F. The cleared ranges are the seven records from +$0E for $B0 bytes each, the bag, the gold, $091E, the play time and $0B59, and the $7F:F080 block. The blue test at $84:886D is misdecoded by the disassembly (and #$ff / ora / mvn); the decompilation reads it as and #$01FF, then the table compare. The guidebook (p. 72, OCR) says the party and capsule monsters go back to level 1 with 10 Potions; the level-1 records are the decompilation's reading of $81:ED35, not measured here.
Cited by: Metaprogression
When an Ancient Cave visit ends without a wipe, the party keeps its Iris treasures and its blue-list items and nothing else: the game collects every Iris treasure in the bag, setting its event flag, then every blue-list item in the bag or in any of the seven members' equipment, restores the copy of the party saved at the entrance, gives the collected items back, and adds the time spent inside to the restored play time. Iris treasures are collected from the bag only, and blue items brought in but no longer held are not returned. lufia-ii/cave-exit
About: Lufia II: Rise of the Sinistrals Metaprogression
Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) ·code/bank_004.s#L1355-L1392lda $0b4e.w ; $8913 : $ad, $4e, $0b
sta $7fe757.l ; $8916 : $8f, $57, $e7, $7f
clc ; $891a : $18
adc $0b69.w ; $891b : $6d, $69, $0b
cmp #$3c.b ; $891e : $c9, $3c
bcc br_04_8928 ; $8920 : $90, $06
sec ; $8922 : $38
sbc #$3c.b ; $8923 : $e9, $3c
inc $0b68.w ; $8925 : $ee, $68, $0b
br_04_8928:
sta $0b69.w ; $8928 : $8d, $69, $0b
lda $0b4d.w ; $892b : $ad, $4d, $0b
…Our readingadd the cave's minutes and hours to the cave's total time; add $0B5B to $0B721355–1387$7F:E759 nonzero (a wipe): skip the collecting1389–1392lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_004.s#L1395-L1477ldx #$e202.w ; $8959 : $a2, $02, $e2
stx WMADDL.w ; $895c : $8e, $81, $21
lda #$7e.b ; $895f : $a9, $7e
sta WMADDH.w ; $8961 : $8d, $83, $21
rep #ACCU_8 ; $8964 : $c2, $20
ldy #$0000.w ; $8966 : $a0, $00, $00
sty $58 ; $8969 : $84, $58
br_04_896b:
lda wInventoryItemsAndCounts.w, Y ; $896b : $b9, $8d, $0a
and #$01ff.w ; $896e : $29, $ff, $01
ldx #$0000.w ; $8971 : $a2, $00, $00
br_04_8974:
…Our readingeach bag slot against the nine Iris words at $91:FFCA: list it, set flag 200 + index1403–1439each bag slot: list it if blue ($84:8AF4)1441–1451six equipment words of each of seven member records: list them if blue1453–1474keep the count at $7E:E2001476–1477lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_004.s#L1479-L1617br_04_89fa:
sep #ACCU_8 ; $89fa : $e2, $20
ldx #$b000.w ; $89fc : $a2, $00, $b0
stx WMADDL.w ; $89ff : $8e, $81, $21
lda #$7f.b ; $8a02 : $a9, $7f
sta WMADDH.w ; $8a04 : $8d, $83, $21
ldx #$0000.w ; $8a07 : $a2, $00, $00
br_04_8a0a:
rep #ACCU_8 ; $8a0a : $c2, $20
lda $8b20.w, X ; $8a0c : $bd, $20, $8b
cmp #$ffff.w ; $8a0f : $c9, $ff, $ff
beq br_04_8a36 ; $8a12 : $f0, $22
…Our readingrestore every saved range from $7F:B0001479–1513a wipe: give the saved list from the entrance1517–1546else give each collected item, at least 1 of it1548–1583add the cave's time to the restored play time1585–1610lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_004.s#L1620-L1651Call_04_8af4:
sta $54 ; $8af4 : $85, $54
and #$ff.b ; $8af6 : $29, $ff
ora ($18, X) ; $8af8 : $01, $18
beq br_04_8b1f ; $8afa : $f0, $23
ldx #$0000.w ; $8afc : $a2, $00, $00
br_04_8aff:
cmp $94eea0.l, X ; $8aff : $df, $a0, $ee, $94
beq br_04_8b0f ; $8b03 : $f0, $0a
inx ; $8b05 : $e8
inx ; $8b06 : $e8
cpx #$0052.w ; $8b07 : $e0, $52, $00
…Checked by claude, 2026-11-08 — read the exit routine whole in the disassemblyRevised after a check by a second AI model, 2026-11-08.Checked by a second AI model, 2026-11-08.The exit is $84:890B. The blue test at $84:8AF4 is misdecoded at $8AF6 (and #$ff / ora); the decompilation (src/cave/cave_exit.c#L8-L37) reads and #$01FF and an item of 0 skipped. The guidebook (p. 72-73, OCR) says the same in play terms: red-chest items stay in the cave, blue-chest items can be taken home and brought back in.
Cited by: Metaprogression
A party wipe in the Ancient Cave, a battle there or on its bottom floor that ends with every party member down, ends the visit with nothing gained. The game marks the visit lost, clears the party again without giving back its blue items, and counts the defeat; when the party then leaves, the exit skips the collecting, restores the copy saved at the entrance, and returns only the blue items the party brought in, so that visit's blue-chest finds and Iris treasures are lost. lufia-ii/cave-wipe
About: Lufia II: Rise of the Sinistrals Permadeath
CodeLufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) ·src/cave/cave_reset.c#L136-L170Lufia2ExecutionResult Lufia2AncientCaveDefeat(
const Lufia2Memory *memory, Lufia2CpuState *cpu,
Lufia2PushedChildCall child, void *context) {
if (!child || cpu->program_bank != 0x84u || !cpu->accumulator_is_8_bit ||
cpu->index_is_8_bit || cpu->decimal)
return ExecutionHandoff(cpu, ((uint32_t)cpu->program_bank << 16) | 0x8b9cu);
EmitExecutionCheckpoint(memory, cpu, 0x848b9cu);
OpLoadA(cpu, 0xffu);
OpSta(memory, cpu, WRAM_ANCIENT_CAVE_INVENTORY_MODE);
SimulateJsrFrame(memory, cpu, 0x8ba4u);
Lufia2ExecutionResult result = Lufia2AncientCaveResetParty(memory, cpu, child, context);
if (result.flow != LUFIA2_EXECUTION_RETURNED)
…Our reading$7F:E759 = $FF, then the reset, which skips the saved items when it is nonzero143–148the defeat count +1, held at $FFFF154–160set the map and the reload flags161–168lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_004.s#L1727-L1748lda #$8fff.w ; $8b9c : $a9, $ff, $8f
eor $7fe7.w, Y ; $8b9f : $59, $e7, $7f
jsr Call_04_8888.w ; $8ba2 : $20, $88, $88
rep #ACCU_8 ; $8ba5 : $c2, $20
lda $0b6c.w ; $8ba7 : $ad, $6c, $0b
ina ; $8baa : $1a
bne br_04_8bae ; $8bab : $d0, $01
dea ; $8bad : $3a
br_04_8bae:
sta $0b6c.w ; $8bae : $8d, $6c, $0b
sep #ACCU_8 ; $8bb1 : $e2, $20
lda #$f0.b ; $8bb3 : $a9, $f0
…When an Ancient Cave visit ends without a wipe, the party keeps its Iris treasures and its blue-list items and nothing else: the game collects every Iris treasure in the bag, setting its event flag, then every blue-list item in the bag or in any of the seven members' equipment, restores the copy of the party saved at the entrance, gives the collected items back, and adds the time spent inside to the restored play time. Iris treasures are collected from the bag only, and blue items brought in but no longer held are not returned. Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_003.s#L597-L609lda $7ff8a2.l ; $8401 : $af, $a2, $f8, $7f
cmp #$01.b ; $8405 : $c9, $01
bne br_03_8425 ; $8407 : $d0, $1c
lda wCurrRoomIdx.w ; $8409 : $ad, $ac, $05
cmp #$f1.b ; $840c : $c9, $f1
beq br_03_8414 ; $840e : $f0, $04
cmp #$f0.b ; $8410 : $c9, $f0
bne br_03_841a ; $8412 : $d0, $06
br_03_8414:
jsr $848b9c.l ; $8414 : $22, $9c, $8b, $84Our readingafter a battle: result $7F:F8A2 = 1 on map $F1 or $F0: the defeat routine $84:8B9C597–609Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/battle/battle_outcome.c#L30-L76OpLoadA(cpu, 0xffu);
OpSta(memory, cpu, OpDp(cpu, 0x11u));
OpSta(memory, cpu, OpDp(cpu, 0x12u));
OpLdy(cpu, 6u);
do {
OpLdx(cpu, OpReadX(memory, cpu, OpAbsY(cpu, WRAM_BATTLE_PARTY_RECORDS)));
if (!cpu->zero) {
OpLda(memory, cpu, OpAbsX(cpu, 0x000fu));
OpAndValue(cpu, 0x04u);
if (cpu->zero)
OpStz(memory, cpu, OpDp(cpu, 0x11u));
}
…Our reading$11 stays $FF only if every party record has status bit $04; $12 the same for the enemies30–56every enemy down: result 0; else every member down: result 166–76Checked by claude, 2026-11-08 — read the defeat routine in the decompilation and the disassembly, and the exit's two branchesRevised after a check by a second AI model, 2026-11-08.Checked by a second AI model, 2026-11-08.The defeat routine is $84:8B9C. Its first bytes (A9 FF 8F 59 E7 7F, lda #$ff and sta $7FE759) are decoded by the disassembly as lda #$8fff.w and eor, so the decompilation is quoted for it. The guidebook (p. 72, OCR) says a wipe returns the party to the door at the exit. The code read here doesn't show the map change it makes; the routine sets map byte $05C0 to $F0.
Cited by: Metaprogression, Permadeath
Between visits the game keeps, outside the copy the exit restores, a count of entries and one of wipes, the total time spent in the cave, and the deepest floor reached; what else carries over is the Iris flags and the blue items as the party holds them. lufia-ii/cave-between-visits
About: Lufia II: Rise of the Sinistrals Metaprogression
Codelufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) ·code/bank_004.s#L1121-L1128ldx $0b6a.w ; $879f : $ae, $6a, $0b
inx ; $87a2 : $e8
bne br_04_87a6 ; $87a3 : $d0, $01
dex ; $87a5 : $ca
br_04_87a6:
stx $0b6a.w ; $87a6 : $8e, $6a, $0bOur readingentries +1 at $0B6A, held at $FFFF1121–1128lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_003.s#L4780-L4785Call_03_9e31:
lda wAncientCaveFloorPlus1.l ; $9e31 : $af, $96, $e6, $7f
cmp $000b75.l ; $9e35 : $cf, $75, $0b, $00
bcc br_03_9e3f ; $9e39 : $90, $04
sta $000b75.l ; $9e3b : $8f, $75, $0b, $00Our readingfloor count at or above $0B75: store it there4781–4785Lufia2Decomp: semantic reconstruction of Lufia II: Rise of the Sinistrals (SNES, USA) · src/system/wram.h#L266-L272#define WRAM_ANCIENT_CAVE_TOTAL_HOURS 0x0b68u
#define WRAM_ANCIENT_CAVE_TOTAL_MINUTES 0x0b69u
#define WRAM_ANCIENT_CAVE_ENTRY_COUNT 0x0b6au
#define WRAM_ANCIENT_CAVE_DEFEAT_COUNT 0x0b6cu
#define WRAM_FIELD_REWARD_COUNT_A 0x0b6eu
#define WRAM_FIELD_REWARD_COUNT_B 0x0b70u
#define WRAM_ANCIENT_CAVE_TOTAL_COUNTER 0x0b72uLufia II - Rise of the Sinistrals (USA) · 0x20B20-0x20B58 — $84:8B20, the saved ranges: none covers $0B68-$0B75Lufia II Ancient Cave LiveSplit/USB2SNES definition · lufia-ac.json#L33-L35"name": "Floor01",
"address": "0x0B75",
"value": "0x02",A party wipe in the Ancient Cave, a battle there or on its bottom floor that ends with every party member down, ends the visit with nothing gained. The game marks the visit lost, clears the party again without giving back its blue items, and counts the defeat; when the party then leaves, the exit skips the collecting, restores the copy saved at the entrance, and returns only the blue items the party brought in, so that visit's blue-chest finds and Iris treasures are lost. CodeWhen an Ancient Cave visit ends without a wipe, the party keeps its Iris treasures and its blue-list items and nothing else: the game collects every Iris treasure in the bag, setting its event flag, then every blue-list item in the bag or in any of the seven members' equipment, restores the copy of the party saved at the entrance, gives the collected items back, and adds the time spent inside to the restored play time. Iris treasures are collected from the bag only, and blue items brought in but no longer held are not returned. CodeChecked by claude, 2026-11-08 — read the counters' writes in the disassembly and checked them against the saved ranges decoded from the ROMChecked by a second AI model, 2026-11-08.Checked by a second AI model, 2026-11-08.The names of $0B68 to $0B72 are the decompilation's; the exit adds the hours and minutes and $0B5B into them ($84:8913-$84:894B). The deepest floor at $0B75 holds the count at the time of a build, the number of the floor being built; LiveSplit's Ancient Cave splits read it. Whether these bytes reach the save file is not read here.
Cited by: Metaprogression
The Ancient Cave changes its look and music in three bands of floors: floors 1 to 20, 21 to 40, and 41 to 98 each take their own block set, map header and music, chosen by (floor − 1) ÷ 10 from a 10-entry table; within a band the palette changes every two floors, through four. lufia-ii/cave-themes
code/bank_003.s#L4788-L4794lda wAncientCaveFloorPlus1.l ; $9e3f : $af, $96, $e6, $7f
dea ; $9e43 : $3a
sta $004204.l ; $9e44 : $8f, $04, $42, $00
tdc ; $9e48 : $7b
sta $004205.l ; $9e49 : $8f, $05, $42, $00
lda #$0a.b ; $9e4d : $a9, $0a
sta $004206.l ; $9e4f : $8f, $06, $42, $00Our reading(floor - 1) ÷ 10 on the divider4788–4794lufia2-disasm: a WLA-DX disassembly of Lufia II: Rise of the Sinistrals (USA) · code/bank_003.s#L4830-L4872br_03_9ea2:
tdc ; $9ea2 : $7b
sta $7fe698.l ; $9ea3 : $8f, $98, $e6, $7f
tdc ; $9ea7 : $7b
lda $004214.l ; $9ea8 : $af, $14, $42, $00
tax ; $9eac : $aa
lda $839f4f.l, X ; $9ead : $bf, $4f, $9f, $83
sta $7fe697.l ; $9eb1 : $8f, $97, $e6, $7f
asl ; $9eb5 : $0a
tax ; $9eb6 : $aa
rep #ACCU_8 ; $9eb7 : $c2, $20
lda $839f65.l, X ; $9eb9 : $bf, $65, $9f, $83
…Our readingband = $83:9F4F[(floor - 1) ÷ 10]4831–4837music, map resource, block set and more from word tables by band4838–4852palette pair = table[band base + (floor AND 6) × 3 ÷ 2]4853–4863map header pointer by band × 34864–4872Lufia II - Rise of the Sinistrals (USA) · 0x19F4F-0x19F58 — $83:9F4F: 00 00 01 01 02 02 02 02 02 02Lufia II - Rise of the Sinistrals (USA) · 0x19F65-0x19F6A — $83:9F65, the music by band: $05, $08, $17Checked by claude, 2026-11-08 — read the floor routine's table reads in the disassembly and the band table from the ROMChecked by a second AI model, 2026-11-08.Depth changes four things in the Ancient Cave and, in the code read here, nothing else: which six enemy kinds a floor can hold, the price ceiling of its weapon and armour chests, whether and how often Providence can appear, and the floor's look and music. The same count also picks the fixed bottom map at 99 and is kept as the deepest floor reached. The enemies keep the stats of their monster records; no routine that reads the floor number touches them. lufia-ii/cave-depth
code/bank_003.s#L4040-L4043lda $e696.w ; $9a30 : $ad, $96, $e6
dea ; $9a33 : $3a
asl ; $9a34 : $0a
sta $54 ; $9a35 : $85, $54Each of the 224 monsters has a record reached through a table of 224 offsets at $96:85C0: the battle loader copies its 13-letter name, four words from +$11 to +$17, and four bytes from +$19 to +$1C, which it doubles into words; the routine at $81:FBDB reads the experience and gold it pays as words at +$1D and +$1F; and a list of three-byte entries from +$21, ended by 0, holds the drop: in an entry of kind 3 the low 9 bits name the item and the top 7 bits give the chance in percent. Terror Wave names the four words HP, MP, attack, and defense, the four bytes agility, intelligence, guts, and magic resistance, and the byte at +$0D the level. 132 monsters carry a drop. HP runs up to 65535 (Egg Dragon) and experience up to 60000 (Egg Dragon). CodeThe Ancient Cave has 99 floors, and the game builds each of the first 98 at random as the party reaches it; the 99th is a fixed map. Entering clears the floor count and arriving on the cave's map with a count of 0 sets it to 1; each floor is built with the count as its number and the count rises by one after it, and when the count stands at 99 the game loads the fixed map instead of building one. CodeBetween visits the game keeps, outside the copy the exit restores, a count of entries and one of wipes, the total time spent in the cave, and the deepest floor reached; what else carries over is the Iris flags and the blue items as the party holds them. CodeChecked by claude, 2026-11-08 — listed every instruction in the disassembly whose operand is the floor count at $7F:E696 (long, or absolute with the data bank at $7F) and read eachRevised after a check by a second AI model, 2026-11-08.The readers are the item lists ($83:9048, $83:9062), Providence ($83:9121, $83:912E), the enemy pick ($83:9A30), the floor routine ($83:9E31-$83:9F3A), the arrival ($83:B25D), the floor label ($80:C848) and a diagnostic display ($8E:B1C5). An indexed or indirect read would escape the search. The battle loader copies a monster's stats from its record with no floor term (lufia-ii-tables/monsters).
Cited by: Level scaling
Measured by running the cartridge's own entry, exit and defeat routines in Mesen on a party the probe stages rather than a save: Maxim alone at level 40, with Water spear equipped and Sizzle sword, five Potions and Mega ax in the bag (the three weapons are on the blue-chest list). Entry left Maxim at level 1 with nothing equipped and a bag of 10 Potions followed by the three weapons. After three more Potions and two blue-list weapons (Air whip in the bag, Blaze sword equipped) were added, the exit gave back level 40 and the five Potions, dropped the 13 cave Potions, and put all five blue-list weapons in the bag, the equipped ones included, with nothing equipped. After the defeat routine on a second visit, the bag held only 10 Potions, and the exit that followed gave back the bag from before the visit (Sizzle sword, five Potions, Mega ax) with Water spear, the weapon Maxim had equipped, added to it, and neither weapon found inside. The probe stops each exit at $84:8AE2, before the screen redraw. lufia-ii/cave-visit-measured
Value
{
"probe": {
"home": {
"bag": [
"Sizzle sword",
"Potion ×5",
"Mega ax"
],
"level": 40,
"equipped": "Water spear"
},
"entered": {
"bag": [
"Potion ×10",
"Sizzle sword",
"Mega ax",
"Water spear"
],
"level": 1,
"equipped": null
},
"inside": {
"bag": [
"Potion ×10",
"Sizzle sword",
"Mega ax",
"Water spear",
"Potion ×3",
"Air whip"
],
"level": 1,
"equipped": "Blaze sword"
},
"left": {
"bag": [
"Sizzle sword",
"Potion ×5",
"Mega ax",
"Water spear",
"Air whip",
"Blaze sword"
],
"level": 40,
"equipped": null
},
"defeated": {
"bag": [
"Potion ×10"
],
"level": 1,
"equipped": null
},
"wiped": {
"bag": [
"Sizzle sword",
"Potion ×5",
"Mega ax",
"Water spear"
],
"level": 40,
"equipped": null
}
}
}0x2078A-0x20BC6 — $84:878A-$84:8BC6, the entry, reset, exit and defeat routines, run by the probe (with the routines they call in banks $81 and $82)Checked by claude, 2026-11-08 — ran probes/lufia-ii/cave-visit.mjs: after 300 frames from power-on it stages the bag ($0A8D), party slot list ($0A7B) and Maxim's record ($0BAD: level at +$0E, equipment at +$66), calls $84:878A, $84:890B and $84:8B9C as a JSL would, and reads the bag, level and first equipment slot after eachRevised after a check by a second AI model, 2026-11-08.Probe: probes/lufia-ii/cave-visit.mjsThe weapons are the first five entries of the blue-chest list at $94:EEA0, read from the ROM by the probe; names from the item name table. The probe stops the exit at $84:8AE2, after its item and record work and before it redraws the screen, which a staged call can't finish. The probe doesn't reach the cave from a save, so what leads to the exit in play, the gold, and the other six members aren't measured. Level at record + $0E follows the decompilation's stat growth (GROWTH_RECORD_LEVEL_BYTE). The rules read in the code: lufia-ii/cave-entry, lufia-ii/cave-exit, lufia-ii/cave-wipe.