First of all, C002AB is multiplication routine. It takes m23*m24 and stores it in m26-27 (2 bytes). C002E2 is the division routine.
Here's how the RNG works:
The RNG is stored in 7E0038-7E003B.
The RNG is modified by functions like these (not exhaustive):
Address C00342 STA $23 REP #$20 LDA $3A EOR #$8020 STA $3A LDA $38 ASL A ASL A CLC ADC $38 ADC $3A STA $38 SEP #$20 XBA STA $24 JSR $02AB [multiplication] LDA $27 RTS
Translation: (16 bits) m23:=A AND 0xFF m3A:=m3A XOR 0x8020 A:=4*m38 AND 0xFFFF A:=A+m38 if A>0xFFFF then C:=1 else C:=0 m38:=(A+m3A+C) AND 0xFFFF m24:=m38 >> 8 m26:=m23*m24 return (m26 >> 8) [A]
The function calculates a random number between 0 and (A AND 0xFF)-1. We'll call this function rand(X), for a random number between 0 and X-1.
All jumps to this routine use "JSR $0342"

Encounters

Address C02A89 LDA #$FA JSR $0342 [rand] CMP #$96 BCS $18 [3] CMP #$8E BCC $02 [1] BRA $08 [2] [1] CMP #$32 BCS $0E [3] CMP #$2A BCC $0A [3] [2] LDA #$01 STA $07F9 LDA #$06 STA $07EA [3] RTS
Translation: A:=rand(250) if 142<=A<150 or 42<=A<50 then [encounter]
This determines encounters.

Pre-emptive attack on encounter

Address C086DC LDA $07F9 CMP #$02 BEQ $12 [1] LDA #$C8 JSR $0342 [rand] LDX #$0002 CMP #$BE BCS $06 DEX CMP #$AA BCS $01 DEX [1] TXA STA $159A BEQ $0D RTS
Translation: if m7F9==2 [boss battle] then Type:=0 exit A:=rand(200) if 190<=A<200 then Type:=2 exit if 170<=A<190 then Type:=1 exit Type:=0
Type 0: no pre-empt Type 1: ally pre-empt Type 2: enemy pre-empt
The function determines whether or not a pre-empt occurs. If an ally pre-empt occurs, all allies get a free round to attack first. If an enemy pre-empt occurs, all enemies get a free round to attack first. Boss battles cannot have pre-empts.

Accuracy of physical attacks

Address C08B9D LDA $12,x AND #$00FF PHA LDX $15A1 LDA $12,x AND #$00FF ADC #$0028 SEC SBC $01,s [push value] BCS $03 [1] LDA #$0000 [1] STA $2C PLA SEP #$20 LDA #$05 STA $30 JSR $02E2 [division m32:=int(m2C/m30)] INC $32 INC $32 LDA $32 JSR $0342 DEC $32 CMP $32 BCC $09 [2] LDX $15B0 LDA $35,x ORA #$10 STA $35,x [2] RTS
Translation:
A:=DefAgl AND 0xFF S:=A A:=AtkAgl AND 0xFF A:=A+40 A:=A-S if A<0 then A:=0 m2C:=A m30:=5 m32:=int(m2C/m30)+2 A:=rand(m32) if A==m32-1 then [attack miss] else [attack hit]

Another RNG-related routine

Address C00363 STY $2A REP #$20 LDA $38 ASL A ASL A CLC ADC $38 ADC $3A STA $38 STA $24 SEP #$20 JSR $025F [multiplication] LDY $28 RTS
Y:=m2A AND 0xFFFF A:=4*m38 AND 0xFFFF A:=A+m38 if A>0xFFFF then C:=1 else C:=0 m38:=(A+m3A+C) AND 0xFFFF m24:=m38 return m24*Y >> 16 [Y]
This is another rng-modifying function. The only difference between this function and rand(X) is that address m3A does not XOR by 0x8020, and that the multiplication uses 16-bits of RNG, rather than 8-bit. Call this function rand2(Y)

Initial damage routine

Address C08BDB REP #$20 STZ $0554 LDA $054E [atk] SEC SBC $0550 [def] BCS $06 [1] LDY #$0001 JMP $8C1F [4] [1] STA $2A SEP #$20 LDA #$0A STA $24 LDA $15AB BIT #$80 BNE $02 [2] LSR $24 [2] JSR $0288 [multiplication m26:=m2A(16bit)*m24] LDA #$00 XBA LDA $24 TAY LDX $26 STX $0554 BEQ $0B [3] STX $2C LDA #$0A STA $30 JSR $02E2 [division m32:=int(m2C/m30)] LDY $32 [3] JSR $0363 [rand2] INY [4] LDX $15B0 REP #$21 TYA ADC $0554 STA $0554 CMP #$270F BCC $03 [5] LDA #$270F [5] STA $0554 SEP #$20 RTS
Translation: m554:=0 A:=m54E [atk] A:=A-m550 [def] if A<0 then Damage:=1 exit m2A:=A if [enemy attack] then m24:=5 else m24:=10 m26:=m24*m2A if m26==0 then Damage:=rand2(m24)+1 exit m554:=m26 m2C:=m26 m30:=10 Y:=int(m2C/m30) m554:=m554+rand2(Y)+1 if m554>9999 then m554:=9999 Damage:=m554
This routine calculates the initial damage. This is the final damage if it is magic/item attack. If it is physical attack, there may be critical hit applied later.
This routine only executes if the attack does not miss.

Magic damage (attack value)

Address C0964C LDX $15A1 LDA $13,X JSR $97D1 [?] REP #$20 AND #$00FF PHA LDA $0546 AND #$00FF CLC ADC $01,S [push value] STA $054E LSR A CLC ADC $054E STA $054E PLA SEP #$20 RTS
Translation:
S:=Wisdom [cannot exceed 255] A:=m546 [basepower of spell/item] [cannot exceed 255] A:=A+S A:=A+int(A/2) AtkValue:=A
This routine calculates the attack value of a spell/item.

Critical hit

Address C08A69 LDA #$1E STA $02 LDA $159E [?] BIT #$80 BEQ $02 [1] ASL $02 [1] LDX $15A1 LDA $3C,X LSR A BCC $02 [2] LSR $02 [2] LDA $02 JSR $0342 [RAND] LSR $02 CMP $02 BNE $1C [4] REP #$20 LDA $0554 [DMG] ASL A ADC $0554 [DMG] CMP #$270F BCC $03 [3] LDA #$270F [3] STA $0554 SEP #$20 LDA #$00 JSR $AAD2 [GREATEST ATTACK?] RTS [4] LDA #$14 STA $02 LDA $159E BIT #$80 BEQ $02[5] ASL $02 [5] LDX $15A1 LDA $3C,X LSR A LSR A BCC $02[6] LSR $02 [6] LDA $02 JSR $0342 [RAND] LSR $02 CMP $02 BNE $18 [8] REP #$20 LDA $0054 [DMG] ASL A CMP #$270F BCC $03 [7] LDA #$270F [7] STA $0554 SEP #$20 LDA #$01 JSR $AAD2 [CRUSHING ATTACK?] [8] RTS
Translation:
m2:=30 if [unknown thing] then m2:=2*m2 if [modifier] then m2:=int(m2/2) A:=rand(m2) if A==int(m2/2) then m554:=max(3*m554,9999) exit [greatest attack] m2:=20 if [unknown thing] then m2:=2*m2 if [modifier2] then m2:=int(m2/2) A:=rand(m2) if A==int(m2/2) then m554:=max(2*m554,9999) exit [crushing attack]
This routine first determines whether an attack is a GREATEST ATTACK (1/30 probability). If it is, damage is multiplied by 3, max damage 9999. If an attack is not a GREATEST ATTACK, the routine determines whether an attack is a CRUSHING ATTACK (1/20 probability). If so, damage is multiplied by 2.
This routine only executes if the attack does not miss. The CRUSHING ATTACK part only executes if the attack is not a GREATEST ATTACK.

GameResources/SNES/MagicKnightRayearth/RNG last edited by adelikat on 6/9/2019 7:37 PM
Page History Latest diff List referrers View Source