data/claims/ff1.yamlFinal Fantasy (Disch's disassembly)
Game: Final Fantasy.
Final Fantasy (developer and publisher Square) came out for the Famicom in Japan on 18 December 1987. ff1/release
Q1415970, P178 developer, P123 publisher, and P577 publication date qualified by P291 place and P400 platform — 1987-12-18 (Japan, NES/Famicom), read through the Query Service on 2026-10-20; Wikidata has no North American NES date+1987-12-18T00:00:00ZCited by: Multi-hit attack
The NES version's title screen reads "© 1987 SQUARE" and "© 1990 NINTENDO". ff1/title-screen
Final Fantasy Disassembly/bank_0E.asm#L77-L81@lut_Copyright:
…
; "C 1987 SQUARE "
…
; "C 1990 NINTENDO"Checked by claude-agent, 2026-10-20 — read the copyright table and decoded its tiles against Disch's string commentsBattleRNG returns the next byte of a 256-byte table, indexed by a counter (btl_rngstate) that wraps, so battle draws repeat every 256 calls. ff1/rng
About: Final Fantasy Random number generator
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0F.asm#L13817-L13824BattleRNG:
LDX btl_rngstate
INC btl_rngstate
LDA @Scramble_lut, X
RTSChecked by claude-agent, 2026-10-20 — read BattleRNGCited by: Final Fantasy, Random number generator, Turn order
BattleRNG's table holds $00 twice and never $95, so a battle draw is never $95. ff1/rng-table
About: Final Fantasy Random number generator
CodeFinal Fantasy (USA) ·0x3FD01-0x3FE00 — bank $0F $FCF1-$FDF0, the table; `$00` sits at positions 97 and 110Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L13811-L13824;; IMPORTANT NOTE!!!! ChaosDeath in bank B assumes that calling this routine 256 times consecutively will
;; produce every value between 00,FF.
…
@Scramble_lut:
.INCBIN "bin/0F_FCF1_rngtable.bin"Checked by claude-agent, 2026-10-20 — counted the 256 bytes at ROM offset 0x3FD01 and in the repo's bin/0F_FCF1_rngtable.bin, which are identical: 255 distinct values, `$00` twice, `$95` missing; the game's other table at $F100 holds all 256Disch's comment assumes the table is a permutation. ChaosDeath maps each byte onto one of 122 tiles, two or three bytes per tile, so the missing $95 still leaves every tile reachable.
Cited by: Critical hit, Final Fantasy, Random number generator
RandAX scales a table byte into a range: . ff1/rand-ax
About: Final Fantasy Random number generator
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L5888-L5905SBC $68AF ; subtract to get the range.
…
JSR BattleRNG_L
LDX $68B6
JSR MultiplyXA ; random()*range
…
TXA ; drop the low 8 bits, put high 8 bits in A (effectively: divide by 256)Checked by claude-agent, 2026-10-20 — read RandAX and MultiplyXA (high byte of the product in X)The range is a byte, so a range of 256 wraps to 0; a base damage of 255 adds nothing (damage-roll).
Cited by: Final Fantasy, Random number generator
A character's damage stat rises by 1 whenever a level-up raises Strength to an even number, and by the weapon's damage when it is equipped; the weapon's hit bonus adds to hit rate the same way. ff1/damage-stat
About: Final Fantasy Damage formula
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0B.asm#L1060-L1072LDY #ch_str - ch_stats ; damage goes up 1 pt for each 2pts of strength
…
LDY #ch_dmg - ch_stats ; if yes, add 1 to damage statFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L10919-L10928ADC (tmp), Y ; add to it the weapon's hit bonus
…
ADC (tmp), Y ; add weapon's damage bonusChecked by claude-agent, 2026-10-20 — read the level-up substat changes and the equip routine's @AdjustWeaponCited by: Final Fantasy, Hit chance
A physical attack's hit chance starts at 168; Dark on the attacker costs 40, and Dark on the defender gives 40. Unless the defender is asleep or stunned, it then adds the attacker's hit rate and subtracts the defender's evade. The result is held within 1–255. ff1/hit-chance
About: Final Fantasy Hit chance
Value
{
"base": 168,
"dark": 40
}Final Fantasy Disassembly/bank_0C.asm#L4309-L4332LDA #168 ; base hit chance of 168
…
LDA btl_attacker_ailments ; if attacker has DARK status, penalty of 40 to their hit chance
…
: LDA btl_defender_ailments ; if defender has DARK, bonus of 40 to attacker's hit chanceFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4377-L4399LDA #MATHBUF_HITCHANCE ; add their hit rate to their hit chance
…
JSR CapXYAtFF ; cap at 255
…
LDX btl_defender_evade ; the hit chance.
…
INC math_hitchance ; minimum hit chance of 1Checked by claude, 2026-10-21 — re-read DoPhysicalAttack, L4309-L4402: hit rate and evade are added only in @DefenderMobile; the minimum of 1 comes after both branches join (audit pilot flag)Cited by: Damage formula, Final Fantasy, Hit chance
Against a sleeping or stunned defender, base damage rises by a quarter, and the attacker's hit rate and the defender's evade drop out, so the hit chance stays at 168 apart from Dark's 40 either way. ff1/immobile-defender
About: Final Fantasy Hit chance
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L4363-L4380: LDA btl_defender_ailments
AND #AIL_STUN | AIL_SLEEP
BEQ @DefenderMobile ; if defender alseep or stunned....
LDA math_basedamage ; apply 25% bonus to base damage
…
LDX btl_attacker_hitrate ; This seems strange to me. Shouldn't this be done even if defender
JSR MathBuf_Add ; is immobile? Is this BUGGED?Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4309-L4332 — the Dark adjustments come before the sleep/stun branch, so they apply to immobile defenders tooLDA #168 ; base hit chance of 168
…
LDA btl_attacker_ailments ; if attacker has DARK status, penalty of 40 to their hit chance
…
: LDA btl_defender_ailments ; if defender has DARK, bonus of 40 to attacker's hit chanceChecked by claude, 2026-10-21 — re-read L4309-L4380: Dark's ±40 precedes the branch; the immobile branch jumps past @DefenderMobile (audit pilot flag)A defender with high evade is therefore easier to hit asleep, and an attacker with a hit rate above 0 is harder to land; Disch flags the branch as possibly a bug.
Cited by: Final Fantasy, Hit chance
An attack swings times for hit rate , times a multiplier that FAST raises from 1 to 2; an unarmed Black Belt or Master swings twice as often. ff1/hit-count
About: Final Fantasy Multi-hit attack
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L5656-L5666LDA (btl_ob_charstat_ptr), Y ; num hits = hitrate / 32 + 1Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4407-L4415: LDA btl_attacker_numhits ; get proper number of hits (numhits * mult)
LDX btl_attacker_numhitsmult ; the mult is essentially the multiplier for the FAST spell
JSR MultiplyXAFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8616-L8627INC btlmag_defender_numhitsmult ; Increase hit multiplier
…
LDA #$02 ; and max the multiplier at 2Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L5745-L5748LDY #btlch_numhits ; unarmed BB/master gets 2x as many hitsFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0B.asm#L897-L901LDY #ch_hitrate - ch_stats ; assign Hit Rate bonus
…
ADC lut_LvlUpHitRateBonus, X
JSR CapAAt200 ; cap hit rate at 200Checked by claude-agent, 2026-10-20 — read LoadOneCharacterIBStats, the hit-count step of DoPhysicalAttack, BtlMag_Effect_Fast, and the level-up hit rate bonusLevel-ups add a per-class bonus to hit rate, capped at 200, so the count grows with level; a weapon's hit bonus adds to it as well (damage-stat).
Cited by: Damage formula, Final Fantasy, Hit chance, Multi-hit attack
Each swing rolls 0–200 with RandAX; a roll of 200 always misses, and any other roll hits when it is at most the hit chance. ff1/hit-roll
About: Final Fantasy Hit chance
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L4471-L4494LDX #200
JSR RandAX ; [0,200]
…
JMP @NextHitIteration ; skip if got 200 exactly (guaranteed miss)
…
CMP math_randhit ; if hit chance is < randhit value, then this was a miss. Jump aheadChecked by claude-agent, 2026-10-20 — read @HitLoop to the hit testWith RandAX's scaling, a roll of 200 comes only from the table byte $FF, 1 in 256; a hit chance of 199 or more hits on every roll but 200.
Cited by: Damage formula, Final Fantasy, Hit chance, Multi-hit attack
Each swing that rolls under 200 also rolls damage from the base to , capped at 255; a hit subtracts the defender's absorb, with a minimum of 1, and the swings' damage adds up to one total. ff1/damage-roll
About: Final Fantasy Damage formula
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L4312-L4313LDA btl_attacker_strength ; base damage of attacker's strength valueFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L3994-L3996LDY #btlch_dmg ; IB damage
LDA (btl_ib_charstat_ptr), Y
STA btl_attacker_strengthFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4482-L4526: LDX $6BAD
LDA #$00
JSR RandAX
CLC
ADC $6BAD
STA math_basedamage ; random between [basedmg, basedmg*2]
…
JSR MathBuf_Sub ; subtract defender's absorb
…
INC math_dmgcalc
…
JSR MathBuf_Add16 ; total damage += dmgcalcChecked by claude-agent, 2026-10-20 — read the damage roll, the absorb subtraction and its floor, and the running total; for a character the base is the damage stat (PlayerAttackEnemy_Physical copies btlch_dmg into btl_attacker_strength)Cited by: Damage formula, Final Fantasy, Multi-hit attack
A swing is critical when its roll is at most the crit chance, which is capped at the hit chance; a critical adds the swing's random damage again, with no absorb taken from it. ff1/critical
About: Final Fantasy Critical hit
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L4401-L4405LDA math_hitchance ; crit chance cannot exceed hit chanceFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4514-L4521LDA math_critchance ; see if hit value is <= crit chance (this will be impossible if the attack was a miss)
…
LDX math_basedamage ; add random damage to our total
JSR MathBuf_Add
INC battle_critsconnectedChecked by claude-agent, 2026-10-20 — read the crit cap and the crit test after @MissBecause the test is "at most", a roll of 0 is critical even with a crit chance of 0.
Cited by: Critical hit, Damage formula, Damage modifier, Final Fantasy, Hit chance, Multi-hit attack
A character's crit chance is the equipped weapon's index number, not the crit rate in the weapon's data (no code we read touches that byte); an unarmed Black Belt or Master gets twice their level. ff1/crit-rate-bug
About: Final Fantasy Critical hit
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L5692-L5697LDY #btlch_critrate
AND #$7F
STA (btl_ib_charstat_ptr), Y ; BUGGED - this sets the critical rate to the weapon index,Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L27;; byte 2: Critial rate (BUGGED - not used .. see LoadOneCharacterIBStats for offending code)Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L10916-L10928LDY #0 ; zero Y (our source index)
…
ADC (tmp), Y ; add to it the weapon's hit bonus
STA ch_hitrate, X ; and write it back
INY ; inc source index
…
ADC (tmp), Y ; add weapon's damage bonus
STA ch_dmg, X ; and write backFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L5719-L5743CMP #$02
BEQ @BB_Master ; is it a black belt?
CMP #$08
…
LDY #btlch_wepgfx
LDA (btl_ib_charstat_ptr), Y ; see if they have no weapon equipped
BNE @Done
…
LDY #ch_level - ch_stats ; Unarmed BB's crit rate is 2x his level
LDA (btl_ob_charstat_ptr), Y
ASL A
LDY #btlch_critrate
…Checked by claude, 2026-10-25 — read @ApplyWeapon and the unarmed Black Belt branch of LoadOneCharacterIBStats, then every reader of the weapon table the disassembly names: GetPointerToWeaponData's two callers in bank_0C read byte 3 (L982) and bytes 7 and 6 (L5708-L5713), and UnadjustEquipStats and ReadjustEquipStats in bank_0F, through lut_Weapons, read bytes 0 and 1; none reads byte 2. A read by raw address outside these labels isn't ruled out.Weapon index numbers grow toward the end of the weapon list, so later weapons crit more often than their data says.
Cited by: Critical hit, Damage formula, Final Fantasy
A physical attack gains 40 hit chance and 4 base damage when its category or element matches the defender's, but neither side of a battle can trigger it: a character's attack reads the character's own category and weakness bytes instead of the weapon's, and a monster's attack is matched against a character's, and all four bytes are always 0. ff1/weakness-unreachable
About: Final Fantasy Elemental weakness
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L4334-L4357: LDA btl_attacker_category ; see if attacker category matches defender category
AND btl_defender_category
…
LDA btl_attacker_element ; see if attacker element matches defender elemental weakness
AND btl_defender_elemweakness
…
LDA #MATHBUF_HITCHANCE ; +40 bonus to hit chance
…
LDA math_basedamage ; and +4 bonus to base damageFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L3998-L4004LDY #btlch_category ; BUGGED - this is pulling a player's category (always 0). It should be
…
LDY #btlch_elemweak ; BUGGED - uses player elemental weakness as attack element. This is always 0Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4166-L4172LDY #btlch_category ; IB: assigned category. Always zero? Players don't have categories.
…
LDY #btlch_elemweak ; IB: elemental weakness. (Always zero?)Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L5668-L5673; Players start with no elemental weakness or assigned category
LDA #$00
LDY #btlch_category
STA (btl_ib_charstat_ptr), Y
LDY #btlch_elemweak
STA (btl_ib_charstat_ptr), YChecked by claude-agent, 2026-10-20 — read the match in DoPhysicalAttack, both stat loaders, and where LoadOneCharacterIBStats zeroes the two bytes; Disch flags the character side as BUGGED, and the monster side follows because it ANDs against the same zeroed bytesSo weapons made to slay a category, or to strike with an element, hit like any other weapon.
Cited by: Damage formula, Final Fantasy, Hit chance
A damage spell always connects, for a random value from its power to ; its roll of 0–200 against 148 + the spell's hit rate − the target's magic defense doubles the damage instead of deciding a hit. ff1/spell-damage
About: Final Fantasy Damage formula
Value
{
"base": 148
}Final Fantasy Disassembly/bank_0C.asm#L8283-L8286JSR BtlMag_MarkSpellConnected ; damage spells always connect
JSR BtlMag_LoadBaseHitChance ; load base hit chance (since damage always hits, this becomes more of a "critical" chance)Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8207-L8211LDA #<148 ; base hit chance of 148Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8153-L8171JSR MathBuf_Add ; math_hitchance += spell's base hit rate
…
JSR MathBuf_Sub ; math_hitchance -= defender's magdef
…
JSR MathBuf_Add ; math_basedamage = rand[ spelldamage, spelldamage*2 ]Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8325-L8332BEQ :+ ; if the hit/crit roll was 200, this is NOT a crit
…
ASL math_basedamage ; ... do 2x damageChecked by claude-agent, 2026-10-20 — read BtlMag_Effect_Damage, BtlMag_PrepHitAndDamage, and BtlMag_ApplyDamageCited by: Critical hit, Damage formula, Damage modifier, Final Fantasy
A resisted element halves a damage spell's power and drops the 148 from its doubling chance; a weakness multiplies the power by 1.5 and adds 40 to the chance. ff1/spell-elements
About: Final Fantasy Elemental weakness
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L8288-L8313AND btlmag_defender_elemresist ; see if the defender resists this element
…
JSR BtlMag_ZeroHitChance ; ... zero the hit/crit chance
LSR math_basedamage+1 ; and halve the damage
…
AND btlmag_defender_elemweakness ; see if they are weak to the element
…
JSR MathBuf_Add ; crit bonus of +40
…
; damage *= 1.5Checked by claude-agent, 2026-10-20 — read both element checks; the zeroed chance then still gets the spell's hit rate minus magic defense in BtlMag_PrepHitAndDamage, so a resisted spell can double when the spell's hit rate is highCited by: Damage formula, Damage modifier, Elemental weakness, Final Fantasy
A damage spell's damage and its chance to double come from the spell's power, hit rate, and element, the target's magic defense, resistances, and weaknesses, and two random rolls. No stat of the caster enters either, so Intelligence adds nothing to spell damage. ff1/spell-ignores-caster
About: Final Fantasy Damage formula
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L7116-L7126 LDY #MAGDATA_ELEMENT ; magic's element
LDA (btl_magdataptr), Y
STA btlmag_element
…
LDY #MAGDATA_HITRATE ; hit rate
LDA (btl_magdataptr), Y
STA btlmag_hitrate
…
LDY #MAGDATA_EFFECTIVITY ; and effectivity
LDA (btl_magdataptr), Y
STA btlmag_effectivityFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8283-L8316BtlMag_Effect_Damage:
JSR BtlMag_MarkSpellConnected ; damage spells always connect
JSR BtlMag_LoadBaseHitChance ; load base hit chance (since damage always hits, this becomes more of a "critical" chance)
JSR PutEffectivityInDamageMathBuf ; Load spell effectivity into 'damage' math buffer
…
LDA btlmag_element
AND btlmag_defender_elemresist ; see if the defender resists this element
…
: LDA btlmag_element
AND btlmag_defender_elemweakness ; see if they are weak to the element
…
: JSR BtlMag_PrepHitAndDamage ; Get hit/damage stuff into math buffersFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8153-L8171BtlMag_PrepHitAndDamage:
LDA #MATHBUF_HITCHANCE
LDX btlmag_hitrate
JSR MathBuf_Add ; math_hitchance += spell's base hit rate
…
LDA #MATHBUF_HITCHANCE
LDX btlmag_defender_magdef
JSR MathBuf_Sub ; math_hitchance -= defender's magdef
…
LDA #0
LDX math_basedamage
JSR RandAX
…Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8207-L8211BtlMag_LoadBaseHitChance:
LDA #<148 ; base hit chance of 148
STA math_hitchanceFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8325-L8338BtlMag_ApplyDamage:
LDA math_magrandhit
CMP #200
BEQ :+ ; if the hit/crit roll was 200, this is NOT a crit
JSR BtlMag_DidSpellConnect ; See if the spell connected as a critical
BCC :+ ; if yes...
ASL math_basedamage ; ... do 2x damage
…
JSR MathBuf_Sub16 ; HP -= damageChecked by claude, 2026-10-25 — read BtlMag_Effect_Damage and the routines it calls to the HP subtraction (8153-8171, 8207-8213, 8229-8232, 8256-8260, 8283-8333): every input is a btlmag_ spell value loaded from the spell's 8-byte record at 7116-7126, a btlmag_defender_ value, the constant 148, or a random roll. PreparePlayerMagAttack (7824-7848) copies the caster's ailments, damage, level, hit rate, and class into btlmag_attacker_ variables, none of them read by these routines; it loads no IntelligenceThe disassembly's comment on PrepareEnemyMagAttack (L7928-L7934) says none of the attacker stats it loads are used in magic calculations, and guesses one was meant to be Intelligence.
Cited by: Damage formula, Final Fantasy
TMPR and SABR, whose spell effect adds the spell's power to the target's attack, do nothing when cast on a character: the routine that loads a character's stats for a spell doesn't load attack, and the routine that saves them back skips it. ff1/tmpr-sabr-bug
About: Final Fantasy Damage formula
CodeFinal Fantasy (USA) ·0x30260-0x30267 — TMPR's 8-byte record in lut_MagicData (spell $0E, bank $0C $8250); its effect byte is $0DFinal Fantasy (USA) · 0x303A0-0x303A7 — SABR's record (spell $36, bank $0C $8390); its effect byte is $0DFinal Fantasy Disassembly · Final Fantasy Disassembly/Constants.inc#L56-L60MAGDATA_EFFECT = $04Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8118-L8132 — entry $0D is BtlMag_Effect_AttackUp2 @jumptable_MagicEffect:
.WORD Battle_ShowIneffective ; Spell has no in-battle effect
…
.WORD BtlMag_Effect_AttackUp2Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8645-L8650 LDA btlmag_effectivity ; Add the spell effectivity to the defender's attack power.
CLC
ADC btlmag_defender_strength
BCC :+
LDA #$FF ; cap at 255
: STA btlmag_defender_strengthFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L8027-L8070BtlMag_SavePlayerDefenderStats:
…
LDA btlmag_defender_ailments
…
LDA btlmag_defender_magdef ; magdef?? This is weird because not only does no magic actually change
…
LDA btlmag_defender_hp ; HP
…
LDA btlmag_defender_elemresist ; elemental resistence
…
LDA btlmag_defender_numhitsmult ; hit multiplier
…
…Checked by claude, 2026-10-25 — read TMPR's and SABR's records in the ROM (effect byte 4 is $0D in both) against the effect jump table (8118-8137, entry $0D is AttackUp2), AttackUp2 at 8636-8651, the player load at 7700-7760 (no btlmag_defender_strength), and BtlMag_SavePlayerDefenderStats to its RTS: it writes ailments, magic defense, HP, resistance, hit multiplier, absorb, and evadeThe enemy versions load and save strength (L7915-L7917, L8013-L8015), so the spells work on an enemy. Both spells' hit rate is 0, so AttackUp2's write to $6884, which its comment calls BUGGED, changes nothing in the original game.
Cited by: Final Fantasy
Spells that change an enemy's elemental resistance or weakness, such as XFER, have no effect on enemies; the change is never saved, and attacks read those bytes from the enemy's data in ROM. ff1/resist-spells-bug
About: Final Fantasy Elemental weakness
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L7975-L8017;; This routine does not save 'btlmag_defender_elemresist' anywhere, and therefore
;; spells which change enemy resistence (like XFER, AFIR, etc) have no effect when cast
;; on enemies.
…
BtlMag_SaveEnemyDefenderStats:
…
LDA btlmag_defender_hp ; update their HP
…
LDA btlmag_defender_absorb
…
LDA btlmag_defender_numhitsmult ; their hit multiplier
…
…Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L7898-L7903INY ; Y = ENROMSTAT_ELEMWEAK
LDA (btl_entityptr_obrom), Y ; elemental weakness from ROM
STA btlmag_defender_elemweakness
INY ; Y = ENROMSTAT_ELEMRESIST
LDA (btl_entityptr_obrom), Y ; elemental resistance from ROM
STA btlmag_defender_elemresist ; BUGGED - loaded from ROM instead of RAM. Contributes to XFER bugFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4044-L4046LDY #ENROMSTAT_ELEMWEAK ; elemental weakness from ROM
LDA ($86), Y ; BUGGED - it should be taking this from enemy RAM stats, not from ROM stats
STA btl_defender_elemweaknessChecked by claude, 2026-10-25 — read BtlMag_SaveEnemyDefenderStats whole (L7982-L8017): it stores HP, absorb, hit multiplier, ailments, morale, evade, and strength back to enemy RAM, and neither elemental byte; its player counterpart does store elemresist (L8050-L8051). Read both loaders: the magic one takes both elemental bytes through btl_entityptr_obrom and the physical one the weakness through ($86) with the ENROMSTAT_ offsetsCited by: Final Fantasy
At each level-up, an unarmed Black Belt or Master gets absorb equal to their level and a damage stat of twice their level, whatever armor they wear. ff1/bb-armor-bug
About: Final Fantasy Damage formula
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0B.asm#L174-L184LDY #ch_level - ch_stats ; reaches here if no weapon equipped. Get the level
…
LDY #ch_absorb - ch_stats ; Absorb = Level -- BUGGED: This is the infamous BB Armor Bug
…
LDY #ch_dmg - ch_stats ; Damage = 2*LevelChecked by claude-agent, 2026-10-20 — read LvlUp_AdjustBBSubStats; it checks the four weapon slots onlyCited by: Final Fantasy
Measured in the ROM over all 256 battle-RNG states, one swing with base damage 20, hit rate 10, and crit chance 1 against evade 6 and absorb 4 hits 221 times and is critical 4 times; with the attacker in Dark it hits 170 times, and against a sleeping defender 216 times. ff1/hit-loop-measured
About: Final Fantasy Hit chance
Value
{
"probe": {
"one-hit": {
"hits": 221,
"crits": 4,
"missed": 35,
"min": 16,
"max": 66
},
"dark-attacker": {
"hits": 170,
"crits": 4,
"missed": 86
},
"asleep-defender": {
"hits": 216,
"crits": 4,
"missed": 40,
"min": 21
}
}
}0x3269C-0x328E3 — bank $0C $A68C-$A8D3, the math of DoPhysicalAttack the probe runs, skipping the animation at $A775-$A7C8Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4307-L4591 — DoPhysicalAttack's mathLDA #168
STA math_hitchance
…
AND #AIL_DARK
BEQ :+
LDA math_hitchance
SEC
SBC #40
…
AND #AIL_STUN | AIL_SLEEP
BEQ @DefenderMobile
…
…Checked by claude-agent, 2026-10-25 — Read DoPhysicalAttack's math (bank_0C.asm L4307-4591) at the pinned commit: hit chance 168, 40 off for a Dark attacker, the hit rate and evade applied only to a mobile defender, a roll against the hit chance and then the crit chance; the counts are the probe's run of that code in the ROM over all 256 states.Probe: probes/ff-dq/ff1-battle.mjsA permutation table would give 3 criticals at crit chance 1 (table bytes 0–2 roll 0 or 1); the doubled $00 gives 4 (rng-table). The hit chance is 168 + 10 − 6 = 172, and 221 bytes roll 172 or less.
Cited by: Critical hit, Final Fantasy, Hit chance, Random number generator
Measured the same way, four swings with base damage 40, hit rate 100, and crit chance 20 against evade 40 and absorb 10 land 1,020 of 1,024 swings, 109 of them critical, for 129–413 damage; with FAST, eight swings land 2,040 of 2,048, 213 critical. ff1/multi-hit-measured
About: Final Fantasy Multi-hit attack
Value
{
"probe": {
"four-hits": {
"swings": 4,
"hits": 1020,
"crits": 109,
"min": 129,
"max": 413
},
"four-hits-fast": {
"swings": 8,
"hits": 2040,
"crits": 213
}
}
}0x3269C-0x328E3 — bank $0C $A68C-$A8D3, as in hit-loop-measuredFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4407-L4415 — the hit count, numhits × multiplierLDA btl_attacker_numhits
LDX btl_attacker_numhitsmult
JSR MultiplyXA
STA math_numhitsChecked by claude-agent, 2026-10-25 — Read the hit count (bank_0C.asm L4407-4415: numhits times the FAST multiplier, at least 1) at the pinned commit; the swing, hit, critical, and damage totals are the probe's run of DoPhysicalAttack in the ROM over all 256 states.Probe: probes/ff-dq/ff1-battle.mjsCited by: Final Fantasy, Multi-hit attack
A level-up that raises a character's Agility also raises their evade by 1, up to 200. ff1/evade-agility
About: Final Fantasy Hit chance
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0B.asm#L1074-L1082: LDY #ch_evade - ch_stats ; evade goes up 1 if agility went up
LDA @statupbuffer+1
BEQ :+ ; did agility go up?
…
CMP #201 ; cap at 200Checked by claude-agent, 2026-10-20 — read the level-up substat changes after the damage statStarting evade comes from each class's table of starting stats (bank_0F.asm L1856-L1857), not from Agility.
Cited by: Final Fantasy, Hit chance, Turn order
A character's RUN always succeeds when the party strikes first and always fails in a formation marked no-run; otherwise it succeeds when the character's Luck exceeds RandAX(0, level + 15), but the level is read from the wrong place: Disch notes the code reads another character's ailment byte or unrelated memory. ff1/run
About: Final Fantasy Fleeing
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L3755-L3790Battle_PlayerTryRun:
…
LDA btl_strikingfirst ; are we striking first?
BNE @Success ; If yes, run success is guaranteed
…
AND #$01 ; if the 'no run' bit is set in the formation,
BNE @Fail ; then failure is guaranteed.
…
; Run if: Luck > random[0, level+15]
…
; The problem is... the game is BUGGED and reads the wrong value for the level.. it ends up reading
; the ailment byte for 2 players after this one (for top 2 slots) or other garbage memory for the
…Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L3807-L3819LDA btl_mathbuf+2 ; success if low byte was nonzero (if luck > randomval)
BNE @Success ; failure if zero (luck <= randomval)
…
LDA #BTLMSG_CANTRUN ; on failure, print 'Can't Run'
…
LDA #BTLMSG_CLOSECALL ; on success, print 'Close Call....'
…
STA btl_result ; Set the battle result to 3 (party ran)Checked by claude-agent, 2026-10-20 — read Battle_PlayerTryRun to the double return; the level offset is applied to the in-battle stat pointer instead of the character's stats, as Disch's comment saysAgility appears nowhere in the routine; outside the variable list, ch_agil appears only in party creation, the status screen, and the battle-start check (first-strike).
Cited by: Final Fantasy, Fleeing, Turn order
The NES manual says running depends on agility: "There is no guarantee that your escape will be successful — it depends on your agility level." ff1/run-manual
About: Final Fantasy Fleeing
ManualdisputedFinal Fantasy Explorer's Handbook (NES instruction booklet, North America) ·p. 19, RUNIf you are overpowered, you can try to RUN. There is no guarantee that your escape will be successful — it depends on your agility level.Checked by claude-agent, 2026-10-20 — read on the scan (PDF page 11); the OCR text drops the dashDisputed: The code reads Luck and a misread level, not Agility (run).
Cited by: Final Fantasy, Fleeing
On an active enemy's turn, it flees when its morale is below twice the party leader's level, or when morale minus twice that level plus RandAX(0, 50) is below 80. ff1/enemy-flees
About: Final Fantasy Fleeing
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L6778-L6810STA $9E ; $9E = 2*level of party leader
…
; V = X + Morale - L
…
; X = random number between [$00,$32]
…
; if V is less than $50, the enemy will run!
…
BCC @RunAway ; run if morale < 2*level_of_leader
…
LDX #$32
JSR RandAX ; random between [$00-$32]
…Checked by claude-agent, 2026-10-20 — read the morale check at @EnemyActive_AndNotConfused; a sleeping, stunned, or confused enemy skips itCited by: Final Fantasy, Fleeing
Each round, DoBattleRound lists the 9 enemy slots and 4 characters and shuffles them with 16 swaps of two random positions; no stat enters the order. ff1/turn-order
About: Final Fantasy Turn order
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L3181-L3183lut_InitialTurnOrder:
.BYTE $00, $01, $02, $03, $04, $05, $06, $07, $08 ; enemy IDs
.BYTE $80, $81, $82, $83 ; character IDsFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L3199-L3244DoBattleRound:
LDY #$0D ; initialize turn order buffer
…
; Shuffle the turn order. This is done by looping 16 times, each time
; it will pick 2 random entries in the turn order table and swap them.
…
; Note that this is suboptimal, since it's more likely for an entry to
…
JSR RandAX ; pick two random indexes
…
LDA btl_turnorder, Y ; swap those entries in the turn orderChecked by claude-agent, 2026-10-20 — read DoBattleRound through @PerformBattleTurnLoop; each index is RandAX(0, 12) from the battle table, and the loop then walks the 13 entries in order, skipping empty enemy slotsDisch calls the shuffle suboptimal because an entry is more likely to stay where it started than under a full shuffle, and the characters start last.
Cited by: Final Fantasy, Turn order
The NES manual says agility sets the order: "Each character's agility, regardless of enemy or ally, dictates the order of execution." ff1/turn-order-manual
About: Final Fantasy Turn order
ManualdisputedFinal Fantasy Explorer's Handbook (NES instruction booklet, North America) ·p. 26, Battle Techniques, Run as a StrategyEach character's agility, regardless of enemy or ally, dictates the order of execution.Checked by claude-agent, 2026-10-20 — read on the scan (PDF page 15)Disputed: The code shuffles the order at random and reads no stat (turn-order).
Cited by: Final Fantasy, Turn order
At the start of a battle, unless the formation is marked no-run, the game draws with of the party leader: below 11 the party is surprised and loses its first round of commands, and from 90 the party strikes first and the enemies skip the first round. ff1/first-strike
About: Final Fantasy Turn order
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0C.asm#L381-L437AND #$01 ; see if "no run" bit is set. If it is, there is no strike first/surprised check
…
; S = (leaders_agility + leaders_luck) / 8
; V = random[S+S, S+100] - surpised_rate
…
; if V >= 90, party strikes first
…
LDA ch_agil
CLC
ADC ch_luck
…
CMP #11
…Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L3259-L3260LDA btl_strikingfirst ; if the party is striking first
BNE @NextTurn ; skip their turnChecked by claude-agent, 2026-10-20 — read the battle setup from the no-run test to BattleLogicLoop, and the enemy-turn skip in DoBattleRound; the result is clipped at 0 before the comparisonsDisch flags the surprise threshold as possibly off by one ("should this be 10 instead of 11?"). Striking first also guarantees a successful RUN (run).
Cited by: Final Fantasy, Fleeing, Turn order
On the overworld, a step onto a tile marked for fights starts a battle when the battle-step generator returns less than 10, or less than 3 aboard the ship; in dungeons and towns the threshold is a per-map rate. ff1/encounter-rate
About: Final Fantasy Random encounter
Value
{
"overworld": 10,
"ship": 3,
"of": 256
}Final Fantasy Disassembly/bank_0F.asm#L1187-L1197@Fighting:
LDA #10 ; 10 / 256 chance of getting in a random encounter normally
…
LDA #3 ; ... 3 / 256 chance instead (more infrequent battles at sea)
…
JSR BattleStepRNG ; get a random number for battle steps
CMP tmp ; compare it to our chance
BCC @DoEncounter ; if the random number < our odds -- do a random encounterFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L3298-L3304SMMove_Battle:
…
JSR BattleStepRNG ; get a pseudo-random number from the battle step RNG
CMP battlerate ; if that number is >= the battle rate for this map...Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L3756-L3757LDA lut_BattleRates+1, X ; get this map's rate (+1 because first entry is for overworld [unused])
STA battlerate ; and record itChecked by claude-agent, 2026-10-20 — read OWCanMove's @Fighting branch, SMMove_Battle, and the standard-map loader; a tile's second property byte marks it for fights (L1145)The overworld entry of lut_BattleRates is loaded but unused, since the overworld rate is hard-coded (L1771-L1773).
Cited by: Final Fantasy, Random encounter
GetBattleFormation picks one of the area's 8 formations by indexing lut_RNG with a counter that rises by 1 per battle; the low 6 bits select formations 0–3 with 12 chances in 64 each, 4 and 5 with 6, 6 with 3, and 7 with 1. ff1/encounter-formation
About: Final Fantasy Random encounter
Value
[ 12, 12, 12, 12, 6, 6, 3, 1 ]
Final Fantasy Disassembly/bank_0F.asm#L1293-L1299INC battlecounter ; increment the battle counter
LDX battlecounter ; and put it in X
LDA lut_RNG, X ; use it as seed to get a random number
AND #$3F ; drop the 2 high bits of the random number
TAX ; and put in X
LDY lut_FormationWeight, X ; use that to index the formation weight LUT to know which formation to useFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L1357-L1365lut_FormationWeight:
.BYTE 0,0,0,0,0,0, 0,0,0,0,0,0 ; 12/64 chance of formation 0
…
.BYTE 7 ; 1/64Checked by claude-agent, 2026-10-20 — read GetBattleFormation and counted the weight table's 64 entriesBecause lut_RNG holds every byte once (lut-rng), 256 battles in a row draw each formation exactly in proportion to its weight.
Cited by: Final Fantasy, Random encounter, Random number generator
lut_RNG, the 256-byte table at $F100, holds every byte from $00 to $FF exactly once. ff1/lut-rng
About: Final Fantasy Random number generator
CodeFinal Fantasy (USA) ·0x3F110-0x3F20F — bank $0F $F100-$F1FF, lut_RNGFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L11326-L11334;; RNG scrambling lookup table [$F100 :: 0x3F110]
…
;; This table is $100 bytes in size, and simply consists of every number
;; between $00-FF in a scrambled order.
…
lut_RNG:
.INCBIN "bin/0F_F100_rngtable.bin"Checked by claude-agent, 2026-10-20 — counted the 256 bytes at ROM offset 0x3F110: 256 distinct values, identical to the repo's bin/0F_F100_rngtable.binIt is a different table from BattleRNG's (rng-table), which is not a permutation.
Cited by: Final Fantasy, Random encounter, Random number generator
BattleStepRNG returns lut_RNG[i] for a counter that steps by 1 per call; each time it wraps to 0, a sign byte gains $A0, and its top bit sets the direction of the next pass. ff1/rng-step
About: Final Fantasy Random number generator
CodeFinal Fantasy Disassembly ·Final Fantasy Disassembly/bank_0F.asm#L1315-L1345;; Random numbers are generated by stepping through a RNG LUT. Once it
;; cycles through the entire LUT, it cycles through it again -- potentially
;; in a reversed direction. Which direction it's going depends on battlestep_sign.
…
BattleStepRNG:
BIT battlestep_sign ; see if sign indicates a decrement
BMI @Negative
…
ADC #$A0
STA battlestep_sign
…
LDX battlestep ; put battlestep in X
…Checked by claude-agent, 2026-10-20 — read BattleStepRNG; adding $A0 mod 256 cycles the sign byte through 8 values, 4 of them with the top bit setEncounter checks and formation picks draw from lut_RNG through separate counters (encounter-rate, encounter-formation); battle rolls use BattleRNG's own table (rng).
Cited by: Final Fantasy, Random encounter, Random number generator
A new character's hit rate is 10 as a Fighter, 7 as a Red Mage, and 5 in the other four classes; evade is 53 for the Fighter, Black Belt, and White Mage and 58 for the Thief, Red Mage, and Black Mage. ff1/class-start-hit-evade
About: Final Fantasy Hit chance
Value
{
"hitRate": {
"Fighter": 10,
"Thief": 5,
"Black Belt": 5,
"Red Mage": 7,
"White Mage": 5,
"Black Mage": 5
},
"evade": {
"Fighter": 53,
"Thief": 58,
"Black Belt": 53,
"Red Mage": 58,
"White Mage": 53,
"Black Mage": 58
}
}0x3050-0x30AF — bank $00 $B040-$B09F, lut_ClassStartingStats, 16 bytes per class in class order; bytes 8 and 9 are hit rate and evadeFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L1852-L1857LDA lut_ClassStartingStats+7, Y ; sub stats
STA ch_dmg, X
LDA lut_ClassStartingStats+8, Y
STA ch_hitrate, X
LDA lut_ClassStartingStats+9, Y
STA ch_evade, XFinal Fantasy Disassembly · Final Fantasy Disassembly/Constants.inc#L494lut_ClassStartingStats = $B040 ; BANK_STARTINGSTATSFinal Fantasy Disassembly · Final Fantasy Disassembly/Constants.inc#L356-L361CLS_FT = $00
…
CLS_BM = $05Checked by claude-agent, 2026-10-21 — read the six 16-byte rows at ROM offset 0x3050 (bank $00 is the ROM's first 16 KB after the header) and the loader in NewGame_LoadStartingStats, which indexes the table by class × 16Each level-up adds 3 to the hit rate of a Fighter, Black Belt, Knight, or Master, 2 for a Thief, Red Mage, Ninja, or Red Wizard, and 1 for a White or Black Mage or Wizard, up to 200. ff1/hit-rate-growth
About: Final Fantasy Hit chance
Value
{
"Fighter": 3,
"Thief": 2,
"Black Belt": 3,
"Red Mage": 2,
"White Mage": 1,
"Black Mage": 1,
"Knight": 3,
"Ninja": 2,
"Master": 3,
"Red Wizard": 2,
"White Wizard": 1,
"Black Wizard": 1,
"cap": 200
}Final Fantasy Disassembly/bank_0B.asm#L1183-L1187;; lut - Hit rate bonus for each class (assigned at level up) [$9DDC :: 0x2DDEC]
…
lut_LvlUpHitRateBonus:
.BYTE 3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1
; FT TH BB RM WM BM KN NJ MA RW WW BWFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0B.asm#L897-L901LDY #ch_hitrate - ch_stats ; assign Hit Rate bonus
…
ADC lut_LvlUpHitRateBonus, X
JSR CapAAt200 ; cap hit rate at 200Checked by claude-agent, 2026-10-21 — read the bonus table and the level-up code that indexes it by class IDA Fighter's hit rate at level is before weapons, so it swings twice (hit-count, at 32) from level 9 unarmed, level 7 with the Rapier, or level 5 with the Small Knife.
A new game zero-fills every character's stat page, weapon and armor slots included, so the party starts unarmed, with 400 gold. ff1/starting-party
About: Final Fantasy Hit chance
Value
{
"weapons": "none",
"gold": 400
}Final Fantasy Disassembly/bank_0F.asm#L88-L93LDX #$00 ; Loop $100 times to fill each page of unsram
: LDA lut_InitUnsramFirstPage, X; Page 0 of unsram is loaded from this table
STA unsram, X
…
LDA #0 ; stat page filled with zeros (proper stats will be assigned
STA ch_stats, X ; later after party generation)Final Fantasy Disassembly · Final Fantasy Disassembly/variables.inc#L384ch_weapons = ch_stats + $18 ; 4Final Fantasy Disassembly · Final Fantasy Disassembly/variables.inc#L333gold = unsram + $1C ; 3 bytesFinal Fantasy (USA) · 0x302C-0x302E — bank $00 $B01C-$B01E in lut_InitUnsramFirstPage ($B000), the starting gold, $000190Checked by claude-agent, 2026-10-21 — read the power-on fill and NewGame_LoadStartingStats (L1811-L1868), which sets HP, MP, and stats but no equipment; the three gold bytes are $90 $01 $00, 400 little-endianThe 40 weapons add from 0 to 50 to hit rate: 0 for both nunchucks, the Iron Hammer, and four of the six staves; 10 for early blades such as the Small Knife and Short Sword; 35 for the Defense, CatClaw, Katana, and Xcalber; and 50 for the Masmune. ff1/weapon-hit-bonus
About: Final Fantasy Hit chance
Value
{
"byBonus": {
"0": 7,
"5": 5,
"10": 8,
"15": 9,
"20": 3,
"25": 2,
"30": 1,
"35": 4,
"50": 1
},
"byWeapon": {
"Wooden Nunchuck": 0,
"Small Knife": 10,
"Wooden Staff": 0,
"Rapier": 5,
"Iron Hammer": 0,
"Short Sword": 10,
"Hand Axe": 5,
"Scimtar": 10,
"Iron Nunchuck": 0,
"Large Knife": 10,
"Iron Staff": 0,
"Sabre": 5,
"Long Sword": 10,
"Great Axe": 5,
"Falchon": 10,
"Silver Knife": 15,
"Silver Sword": 15,
"Silver Hammer": 5,
"Silver Axe": 10,
"Flame Sword": 20,
"Ice Sword": 25,
"Dragon Sword": 15,
"Giant Sword": 20,
"Sun Sword": 30,
"Coral Sword": 15,
"Were Sword": 15,
"Rune Sword": 15,
"Power Staff": 0,
"Light Axe": 15,
"Heal Staff": 0,
"Mage Staff": 10,
"Defense": 35,
"Wizard Staff": 15,
"Vorpal": 25,
"CatClaw": 35,
"Thor Hammer": 15,
"Bane Sword": 20,
"Katana": 35,
"Xcalber": 35,
"Masmune": 50
}
}0x30010-0x3014F — bank $0C $8000-$813F, lut_WeaponData, 8 bytes per weapon; byte 0 is the hit bonusFinal Fantasy (USA) · 0x2B9CD-0x2BB0C — bank $0A $B9BD-$BAFC, the names of items $1C-$43, the 40 weapons in table orderFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L21-L35;; Weapon data! [$8000 :: 0x30010]
;;
;; 8 bytes per weapon, 40 weapons ($140 bytes total)
;;
;; byte 0: Hit rate
…
lut_WeaponData:Final Fantasy Disassembly · Final Fantasy Disassembly/Constants.inc#L452lut_ItemNamePtrTbl = $B700 ; BANK_ITEMSFinal Fantasy Disassembly · Final Fantasy Disassembly/Constants.inc#L230WPNID_XCALBUR = $27Checked by claude-agent, 2026-10-21 — read byte 0 of the 40 weapon records and decoded the item names through lut_ItemNamePtrTbl with the disassembly's table_standard.tbl; weapon IDs count from 1, so Disch's WPNID_XCALBUR, $27, is record 38, the XcalberNames are the game's own, with its weapon-type icon written as a word (Small Knife is "Small" and a knife icon). Equipping adds the bonus to hit rate (damage-stat).
Shop 1, the first weapon shop in lut_ShopData, sells the Wooden Staff, Small Knife, Wooden Nunchuck, Rapier, and Iron Hammer, with hit bonuses of 0, 10, 0, 5, and 0 and damage of 6, 5, 12, 9, and 9: the most accurate of them, the Small Knife, deals the least damage. ff1/first-weapon-shop
About: Final Fantasy Hit chance
Value
{
"hitBonus": {
"Wooden Staff": 0,
"Small Knife": 10,
"Wooden Nunchuck": 0,
"Rapier": 5,
"Iron Hammer": 0
},
"damage": {
"Wooden Staff": 6,
"Small Knife": 5,
"Wooden Nunchuck": 12,
"Rapier": 9,
"Iron Hammer": 9
}
}0x38312-0x38313 — bank $0E $8302, shop 1's pointer in lut_ShopData, $838FFinal Fantasy (USA) · 0x3839F-0x383A4 — bank $0E $838F-$8394, item IDs $1E $1D $1C $1F $20 and the 0 that ends the listFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0E.asm#L4872-L4879LDA shop_id ; get the shop ID
ASL A ; double it
…
LDA lut_ShopData, X ; load up the pointer to shop's inventoryFinal Fantasy (USA) · 0x30010-0x3014F — bank $0C $8000-$813F, lut_WeaponData; records 0-4 are these five weaponsFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L21-L26;; byte 0: Hit rate
;; byte 1: DamageFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L10916-L10928ADC (tmp), Y ; add to it the weapon's hit bonus
STA ch_hitrate, X ; and write it back
INY ; inc source index
…
ADC (tmp), Y ; add weapon's damage bonus
STA ch_dmg, X ; and write backChecked by claude, 2026-10-25 — followed shop 1's pointer in the table at ROM offset 0x38310, named the five item IDs as in weapon-hit-bonus, and read bytes 0 and 1 of weapon records 0-4; shop 0 has no stock, and shops 2-6 hold the other weapon lists. ReadjustEquipStats (bank_0F L10909-L10928) adds a weapon's byte 0 to the character's hit rate and byte 1 to its damageShop 1 is the weapon shop in Coneria, the town beside the starting point; Nintendo Power's guide lists Coneria's weapons as shop 1's five. ff1/first-weapon-shop-town
About: Final Fantasy Hit chance
MagazineFinal Fantasy (Nintendo Power Player's Strategy Guide, Volume 17) ·p. 10, Coneria Town, Weapons ShopWeapons Shop
Wooden Staff 5 G
Small Knife 5 GChecked by claude, 2026-10-21 — found the list in the scan's text layer: Wooden Staff, Small Knife, Wooden Nunchuck, Rapier, Iron Hammer, shop 1's stock (first-weapon-shop)Matched by stock, not yet traced from the town's map tiles to the shop ID.
Across the 128 enemy records, evade runs from 0 (Scum) to 144 (the Air elemental), with a median of 48; 31 records sit below 25, and six reach 100 or more: Air, Nitemare (132), Frost D and Sphinx (120), Wraith (108), and Chaos (100). ff1/enemy-evade
About: Final Fantasy Hit chance
Value
{
"median": 48,
"byEvade": {
"0": 1,
"4": 2,
"6": 3,
"9": 1,
"12": 5,
"18": 2,
"22": 1,
"24": 16,
"28": 1,
"30": 3,
"36": 11,
"42": 7,
"45": 1,
"46": 1,
"48": 20,
"54": 4,
"56": 1,
"60": 7,
"62": 1,
"66": 1,
"72": 17,
"78": 3,
"84": 2,
"90": 3,
"96": 7,
"98": 1,
"100": 1,
"108": 1,
"120": 2,
"132": 1,
"144": 1
},
"byEnemy": [
{
"id": 0,
"name": "IMP",
"evade": 6
},
{
"id": 1,
"name": "GrIMP",
"evade": 9
},
{
"id": 2,
"name": "WOLF",
"evade": 36
},
{
"id": 3,
"name": "GrWOLF",
"evade": 54
},
{
"id": 4,
"name": "WrWOLF",
"evade": 42
},
{
"id": 5,
"name": "FrWOLF",
"evade": 54
},
{
"id": 6,
"name": "IGUANA",
"evade": 24
},
{
"id": 7,
"name": "AGAMA",
"evade": 36
},
{
"id": 8,
"name": "SAURIA",
"evade": 24
},
{
"id": 9,
"name": "GIANT",
"evade": 48
},
{
"id": 10,
"name": "FrGIANT",
"evade": 48
},
{
"id": 11,
"name": "R.GIANT",
"evade": 48
},
{
"id": 12,
"name": "SAHAG",
"evade": 72
},
{
"id": 13,
"name": "R.SAHAG",
"evade": 78
},
{
"id": 14,
"name": "WzSAHAG",
"evade": 96
},
{
"id": 15,
"name": "PIRATE",
"evade": 12
},
{
"id": 16,
"name": "KYZOKU",
"evade": 24
},
{
"id": 17,
"name": "SHARK",
"evade": 72
},
{
"id": 18,
"name": "GrSHARK",
"evade": 72
},
{
"id": 19,
"name": "OddEYE",
"evade": 84
},
{
"id": 20,
"name": "BigEYE",
"evade": 24
},
{
"id": 21,
"name": "BONE",
"evade": 12
},
{
"id": 22,
"name": "R.BONE",
"evade": 42
},
{
"id": 23,
"name": "CREEP",
"evade": 24
},
{
"id": 24,
"name": "CRAWL",
"evade": 42
},
{
"id": 25,
"name": "HYENA",
"evade": 48
},
{
"id": 26,
"name": "CEREBUS",
"evade": 48
},
{
"id": 27,
"name": "OGRE",
"evade": 18
},
{
"id": 28,
"name": "GrOGRE",
"evade": 30
},
{
"id": 29,
"name": "WzOGRE",
"evade": 54
},
{
"id": 30,
"name": "ASP",
"evade": 30
},
{
"id": 31,
"name": "COBRA",
"evade": 36
},
{
"id": 32,
"name": "SeaSNAKE",
"evade": 48
},
{
"id": 33,
"name": "SCORPION",
"evade": 54
},
{
"id": 34,
"name": "LOBSTER",
"evade": 60
},
{
"id": 35,
"name": "BULL",
"evade": 48
},
{
"id": 36,
"name": "ZomBULL",
"evade": 36
},
{
"id": 37,
"name": "TROLL",
"evade": 48
},
{
"id": 38,
"name": "SeaTROLL",
"evade": 48
},
{
"id": 39,
"name": "SHADOW",
"evade": 36
},
{
"id": 40,
"name": "IMAGE",
"evade": 90
},
{
"id": 41,
"name": "WRAITH",
"evade": 108
},
{
"id": 42,
"name": "GHOST",
"evade": 36
},
{
"id": 43,
"name": "ZOMBIE",
"evade": 6
},
{
"id": 44,
"name": "GHOUL",
"evade": 12
},
{
"id": 45,
"name": "GEIST",
"evade": 46
},
{
"id": 46,
"name": "SPECTER",
"evade": 42
},
{
"id": 47,
"name": "WORM",
"evade": 36
},
{
"id": 48,
"name": "Sand W",
"evade": 62
},
{
"id": 49,
"name": "Grey W",
"evade": 4
},
{
"id": 50,
"name": "EYE",
"evade": 12
},
{
"id": 51,
"name": "PHANTOM",
"evade": 24
},
{
"id": 52,
"name": "MEDUSA",
"evade": 36
},
{
"id": 53,
"name": "GrMEDUSA",
"evade": 72
},
{
"id": 54,
"name": "CATMAN",
"evade": 48
},
{
"id": 55,
"name": "MANCAT",
"evade": 60
},
{
"id": 56,
"name": "PEDE",
"evade": 48
},
{
"id": 57,
"name": "GrPEDE",
"evade": 48
},
{
"id": 58,
"name": "TIGER",
"evade": 48
},
{
"id": 59,
"name": "Saber T",
"evade": 42
},
{
"id": 60,
"name": "VAMPIRE",
"evade": 72
},
{
"id": 61,
"name": "WzVAMP",
"evade": 72
},
{
"id": 62,
"name": "GARGOYLE",
"evade": 45
},
{
"id": 63,
"name": "R.GOYLE",
"evade": 72
},
{
"id": 64,
"name": "EARTH",
"evade": 18
},
{
"id": 65,
"name": "FIRE",
"evade": 42
},
{
"id": 66,
"name": "Frost D",
"evade": 120
},
{
"id": 67,
"name": "Red D",
"evade": 96
},
{
"id": 68,
"name": "ZombieD",
"evade": 24
},
{
"id": 69,
"name": "SCUM",
"evade": 0
},
{
"id": 70,
"name": "MUCK",
"evade": 4
},
{
"id": 71,
"name": "OOZE",
"evade": 6
},
{
"id": 72,
"name": "SLIME",
"evade": 24
},
{
"id": 73,
"name": "SPIDER",
"evade": 30
},
{
"id": 74,
"name": "ARACHNID",
"evade": 24
},
{
"id": 75,
"name": "MANTICOR",
"evade": 72
},
{
"id": 76,
"name": "SPHINX",
"evade": 120
},
{
"id": 77,
"name": "R.ANKYLO",
"evade": 56
},
{
"id": 78,
"name": "ANKYLO",
"evade": 48
},
{
"id": 79,
"name": "MUMMY",
"evade": 24
},
{
"id": 80,
"name": "WzMUMMY",
"evade": 24
},
{
"id": 81,
"name": "COCTRICE",
"evade": 72
},
{
"id": 82,
"name": "PERILISK",
"evade": 72
},
{
"id": 83,
"name": "WYVERN",
"evade": 96
},
{
"id": 84,
"name": "WYRM",
"evade": 60
},
{
"id": 85,
"name": "TYRO",
"evade": 60
},
{
"id": 86,
"name": "T REX",
"evade": 60
},
{
"id": 87,
"name": "CARIBE",
"evade": 72
},
{
"id": 88,
"name": "R.CARIBE",
"evade": 72
},
{
"id": 89,
"name": "GATOR",
"evade": 48
},
{
"id": 90,
"name": "FrGATOR",
"evade": 48
},
{
"id": 91,
"name": "OCHO",
"evade": 24
},
{
"id": 92,
"name": "NAOCHO",
"evade": 24
},
{
"id": 93,
"name": "HYDRA",
"evade": 36
},
{
"id": 94,
"name": "R.HYDRA",
"evade": 36
},
{
"id": 95,
"name": "GUARD",
"evade": 72
},
{
"id": 96,
"name": "SENTRY",
"evade": 96
},
{
"id": 97,
"name": "WATER",
"evade": 72
},
{
"id": 98,
"name": "AIR",
"evade": 144
},
{
"id": 99,
"name": "NAGA",
"evade": 72
},
{
"id": 100,
"name": "GrNAGA",
"evade": 48
},
{
"id": 101,
"name": "CHIMERA",
"evade": 72
},
{
"id": 102,
"name": "JIMERA",
"evade": 60
},
{
"id": 103,
"name": "WIZARD",
"evade": 66
},
{
"id": 104,
"name": "SORCERER",
"evade": 48
},
{
"id": 105,
"name": "GARLAND",
"evade": 12
},
{
"id": 106,
"name": "Gas D",
"evade": 96
},
{
"id": 107,
"name": "Blue D",
"evade": 96
},
{
"id": 108,
"name": "MudGOL",
"evade": 28
},
{
"id": 109,
"name": "RockGOL",
"evade": 24
},
{
"id": 110,
"name": "IronGOL",
"evade": 24
},
{
"id": 111,
"name": "BADMAN",
"evade": 36
},
{
"id": 112,
"name": "EVILMAN",
"evade": 42
},
{
"id": 113,
"name": "ASTOS",
"evade": 78
},
{
"id": 114,
"name": "MAGE",
"evade": 78
},
{
"id": 115,
"name": "FIGHTER",
"evade": 90
},
{
"id": 116,
"name": "MADPONY",
"evade": 22
},
{
"id": 117,
"name": "NITEMARE",
"evade": 132
},
{
"id": 118,
"name": "WarMECH",
"evade": 96
},
{
"id": 119,
"name": "LICH",
"evade": 24
},
{
"id": 120,
"name": "LICH",
"evade": 48
},
{
"id": 121,
"name": "KARY",
"evade": 48
},
{
"id": 122,
"name": "KARY",
"evade": 60
},
{
"id": 123,
"name": "KRAKEN",
"evade": 84
},
{
"id": 124,
"name": "KRAKEN",
"evade": 98
},
{
"id": 125,
"name": "TIAMAT",
"evade": 72
},
{
"id": 126,
"name": "TIAMAT",
"evade": 90
},
{
"id": 127,
"name": "CHAOS",
"evade": 100
}
]
}0x30530-0x30F2F — bank $0C $8520-$8F1F, data_EnemyStats, $14 bytes per enemy; byte 8 is evadeFinal Fantasy (USA) · 0x2D4F0-0x2D95F — bank $0B $94E0-$994F, data_EnemyNames, a pointer per enemy and the namesFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L94-L102;; Data for enemy stats [$8520 :: 0x30530]
;;
;; $80 Enemies * $14 bytes per enemy
…
data_EnemyStats:Final Fantasy Disassembly · Final Fantasy Disassembly/Constants.inc#L41ENROMSTAT_EVADE = $08Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L6215.BYTE ENROMSTAT_EVADE, en_evadeFinal Fantasy Disassembly · Final Fantasy Disassembly/bank_0C.asm#L4048-L4050LDY #en_evade ; evade from RAM
LDA ($84), Y
STA btl_defender_evadeChecked by claude-agent, 2026-10-21 — read byte 8 of all 128 records, which the battle setup copies to en_evade and the attack code loads as btl_defender_evade (hit-chance); names decoded from data_EnemyNames with table_standard.tblNames are the game's abbreviations. Records $77-$7E are the four fiends twice, the second time for the rematches (LICH 24 then 48, KARY 48 then 60, KRAKEN 84 then 98, TIAMAT 72 then 90).
A new game puts the party at overworld tile (153, 165), in land domain $2C, whose eight formation slots all hold 3–5 Imps (evade 6). The domain to its north, $24, gives 3–5 Imps in 48 of 64 battles; its other slots hold 1–3 GrImps (evade 9), 1–2 Wolves (36), a lone Madpony (22), and, 1 time in 64, 3–6 Imps with up to 4 GrImps. ff1/opening-encounters
About: Final Fantasy Hit chance
Value
{
"start": {
"x": 153,
"y": 165,
"domain": "0x2C"
},
"domain2C": [
{
"chance": 64,
"enemies": {
"IMP": [
3,
5
]
}
}
],
"domain24": [
{
"chance": 48,
"enemies": {
"IMP": [
3,
5
]
}
},
{
"chance": 6,
"enemies": {
"GrIMP": [
1,
3
]
}
},
{
"chance": 6,
"enemies": {
"WOLF": [
1,
2
]
}
},
{
"chance": 3,
"enemies": {
"MADPONY": [
1,
1
]
}
},
{
"chance": 1,
"enemies": {
"IMP": [
3,
6
],
"GrIMP": [
0,
4
]
}
}
],
"of": 64,
"evade": {
"IMP": 6,
"GrIMP": 9,
"WOLF": 36,
"MADPONY": 22
}
}0x3020-0x3021 — bank $00 $B010-$B011 in lut_InitUnsramFirstPage, the starting overworld scroll, $92 and $9E (146, 158)Final Fantasy Disassembly · Final Fantasy Disassembly/variables.inc#L325-L326unsram_ow_scroll_x = unsram + $10
unsram_ow_scroll_y = unsram + $11Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0F.asm#L1239-L1259;; For land domains... the entire map is divided into an 8x8 grid. Each element in this
;; grid has it's own domain -- and consists of 32x32 map tiles
…
ADC #$07 ; add 7 to get player X coord
…
ADC #$07 ; add 7 to get player Y coord
…
ORA tmp ; OR with column for the desired domain.Final Fantasy (USA) · 0x2C130-0x2C137 — bank $0B $8120, domain $24's slots, formations $00 $00 $00 $00 $82 $03 $06 $80Final Fantasy (USA) · 0x2C170-0x2C177 — bank $0B $8160, domain $2C's slots, formation $00 eight timesFinal Fantasy (USA) · 0x2C410-0x2CC0F — bank $0B $8400-$8BFF, lut_BattleFormations, 16 bytes each; formation $00 holds enemies $00 (IMP) and $01 (GrIMP) with quantity bytes $35 (A) and $36 $04 (B)Final Fantasy Disassembly · Final Fantasy Disassembly/variables.inc#L777-L785btlform_type = btl_formdata+$0 ; battle type (high 4 bits) -- low 4 bits are pattern table
…
btlform_enids = btl_formdata+$2 ; enemy IDs (4 bytes)
btlform_enqty = btl_formdata+$6 ; enemy quantities (4 bytes)
…
btlform_enqtyB = btl_formdata+$E ; enemy quantities for B formation (2 bytes)Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0B.asm#L2085-L2095LDA a:btlformation ; See if this is a B-formation
BPL :+ ; if it is, replace A-formation values with the B-formation values
…
STX btlform_enids +2 ; zero the enemy ID and min/max for enemies 2,3Final Fantasy Disassembly · Final Fantasy Disassembly/bank_0B.asm#L2645-L2654LDA btlform_enqty, Y ; get min/max for this enemy group
…
AND #$0F
TAX ; put max in X
…
JSR RandAX ; get a random enemy count for this groupChecked by claude-agent, 2026-10-21 — added 7 to the starting scroll as @LandDomain does (row 165 >> 5 = 5, column 153 >> 5 = 4, so domain 5 × 8 + 4); read both domains' slot bytes at lut_Domains (bank $0B $8000) and formations $00, $02, $03, and $06, a high bit selecting the B quantities; chances are the slot weights of encounter-formationEnemy names are the game's. The evade values are from enemy-evade.
The Air elemental (evade 144) is in the random battles of five standard maps, $2F, $30, $32, $33, and $3A, as 2–4 or 3–6 of them in one 12-in-64 slot of the last three, to which $32 and $33 add a second, smaller slot of 1–3 (15 and 18 of 64 in all); Wraith (108) fills 42 of 64 chances on map $25, Frost D (120) 30 of 64 on map $34, and Sphinx (120) 24 of 64 on map $0E and 12 of 64 in four overworld domains. ff1/evasive-enemy-domains
About: Final Fantasy Hit chance
Value
{
"AIR": {
"evade": 144,
"maps": {
"0x2F": 12,
"0x30": 12,
"0x32": 15,
"0x33": 18,
"0x3A": 12
}
},
"NITEMARE": {
"evade": 132,
"maps": {
"0x12": 24,
"0x17": 24,
"0x2F": 6,
"0x30": 6,
"0x3A": 6,
"0x3B": 12
}
},
"Frost D": {
"evade": 120,
"maps": {
"0x0F": 1,
"0x25": 1,
"0x26": 3,
"0x34": 30
}
},
"SPHINX": {
"evade": 120,
"maps": {
"0x0E": 24
},
"overworld": {
"0x03": 12,
"0x04": 12,
"0x0B": 12,
"0x0C": 12
}
},
"WRAITH": {
"evade": 108,
"maps": {
"0x0F": 9,
"0x25": 42,
"0x26": 12
}
},
"of": 64
}Final Fantasy Disassembly/bank_0F.asm#L3298-L3309SMMove_Battle:
…
LDA cur_map ; otherwise, begin a random encounter
CLC ; get the current map, and add 8*8 to it to get past the
ADC #8*8 ; overworld domains.
JSR GetBattleFormation ; Get the battle formation from this map's domainFinal Fantasy (USA) · 0x2C010-0x2C40F — bank $0B $8000-$83FF, lut_Domains, 8 formation bytes for each of 128 domainsFinal Fantasy (USA) · 0x2C410-0x2CC0F — bank $0B $8400-$8BFF, lut_BattleFormationsFinal Fantasy Disassembly · Final Fantasy Disassembly/Constants.inc#L453lut_Domains = $8000 ; BANK_DOMAINS -- MUST be on page boundaryChecked by claude-agent, 2026-10-21 — listed every domain slot whose formation can field each enemy (a nonzero maximum in its A or B quantities) and summed the slot weights of encounter-formation; a standard map's domain is its map number plus $40Counts are chances in 64 that a battle on that map can include the enemy; on maps $2F and $30 Air comes as 0–1 beside a GrNaga. Which places the map numbers are has not been traced here.
Nintendo Power's 1990 strategy guide paces the party by level: about 3 for Garland, "Wait until Level 8 or 9" for the Marsh Cave, and "Level 27 or above to have a good chance against Chaos." ff1/np-levels
About: Final Fantasy Hit chance
Value
{
"garland": 3,
"marshCave": 8,
"chaos": 27
}p. 11, The Light Warriors Prepare For GarlandAt Level 3 your Light Warriors should have no difficultyFinal Fantasy (Nintendo Power Player's Strategy Guide, Volume 17) · p. 22, Northwest CastleWait until Level 8 or 9Final Fantasy (Nintendo Power Player's Strategy Guide, Volume 17) · p. 77, ChaosYour warriors should be at Level 27 or aboveChecked by claude, 2026-10-21 — found each quote in the scan's text layerThe guide gives no level for the Ice Cave, the Earth Cave, or the Sky Castle. A player guide (capa-ff1-guide, a lead) puts the party around level 18 after the Ice Cave and the class change.
Nintendo Power's guide places Wraiths in the Ice Cave and Air elementals in the Sky Castle. ff1/np-enemy-places
About: Final Fantasy Hit chance
Value
{
"WRAITH": "Ice Cave",
"AIR": "Sky Castle"
}p. 79, monster indexWraith
p.43Final Fantasy (Nintendo Power Player's Strategy Guide, Volume 17) · p. 71, Enemies In The Sky CastleAIRChecked by claude, 2026-10-21 — index entries in the scan's text layer; the scout read the p. 43 and p. 71 enemy panels on the rendered pagesFF1Randomizer names the standard maps by index: $0F, $25, and $26 are the Ice Cave's B1–B3, $2F–$33 the Sky Palace's five floors, $34 the revisited Temple of Fiends' first floor, and $3A and $3B its Air and Chaos floors. ff1/map-names
About: Final Fantasy Hit chance
WebFinal Fantasy Randomizer (FF1Randomizer) ·FF1Lib/Enums.csIceCaveB1 = 15,Community code, a lead; not yet confirmed against the ROM's map table. Nintendo Power calls the Sky Palace the Sky Castle.