lorom org $DFFFFD ; expand ROM to 3MB DB "EOF" org $80FFD8 ; expand SRAM to 32KB DB $05 ; overwrites DB $03 org $80809A ; patch copy protection CMP $710000 ; overwrites CMP $702000 org $8080A6 ; patch copy protection CMP $710000 ; overwrites CMP $702000 org $8AEAA3 ; skip gruberik intro dialogue DB $1C,$86,$03 ; L2SASM JMP $8AE784+$0386 org $8AEC82 ; skip gruberik save dialogue DB $1C,$93,$01 ; L2SASM JMP $8AEB1C+$0193 org $8AECFE ; skip gruberik abandon dialogue DB $1C,$32,$02 ; L2SASM JMP $8AEB1C+$0232 org $8AF4E1 ; skip gruberik selan dialogue DB $1C,$D8,$09 ; L2SASM JMP $8AEB1C+$09D8 org $8AF528 ; skip gruberik guy dialogue DB $1C,$1E,$0A ; L2SASM JMP $8AEB1C+$0A1E org $8AF55F ; skip gruberik arty dialogue DB $1C,$67,$0A ; L2SASM JMP $8AEB1C+$0A67 org $8AF5B2 ; skip gruberik tia dialogue DB $1C,$C3,$0A ; L2SASM JMP $8AEB1C+$0AC3 org $8AF61A ; skip gruberik dekar dialogue DB $1C,$23,$0B ; L2SASM JMP $8AEB1C+$0B23 org $8AF681 ; skip gruberik lexis dialogue DB $1C,$85,$0B ; L2SASM JMP $8AEB1C+$0B85 org $8EA349 ; skip ancient cave entrance dialogue DB $1C,$B0,$01 ; L2SASM JMP $8EA1AD+$01B0 org $8EA384 ; reset architect mode, skip ancient cave exit dialogue DB $1B,$E1,$1C,$2B,$02 ; clear flag $E1, L2SASM JMP $8EA1AD+$022B org $8EA565 ; skip ancient cave leaving dialogue DB $1C,$E9,$03 ; L2SASM JMP $8EA1AD+$03E9 org $8EA653 ; skip master intro dialogue DB $1C,$0F,$01 ; L2SASM JMP $8EA5FA+$010F org $8EA721 ; skip master fight dialogue DB $1C,$45,$01 ; L2SASM JMP $8EA5FA+$0145 org $8EA74B ; skip master victory dialogue DB $1C,$AC,$01 ; L2SASM JMP $8EA5FA+$01AC org $8EA7AA ; skip master key dialogue and animation DB $1C,$EE,$01 ; L2SASM JMP $8EA5FA+$01EE org $8EA7F4 ; skip master goodbye dialogue DB $1C,$05,$02 ; L2SASM JMP $8EA5FA+$0205 org $8EA807 ; skip master not fight dialogue DB $1C,$18,$02 ; L2SASM JMP $8EA5FA+$0218 org $94AC45 ; connect ancient cave exit stairs to gruberik entrance DB $67,$09,$18,$68 org $948DE1 ; connect gruberik west border to ancient cave entrance DB $07,$08,$14,$F0 org $948DEA ; connect gruberik south border to ancient cave entrance DB $07,$08,$14,$F0 org $948DF3 ; connect gruberik north border to ancient cave entrance DB $07,$08,$14,$F0 ; archipelago item org $96F9AD ; properties DB $00,$00,$00,$E4,$00,$00,$00,$00,$00,$00,$00,$00,$00 org $9EDD60 ; name DB "AP item " ; overwrites "Key30 " org $9FA900 ; sprite incbin "ap_logo/ap_logo.bin" warnpc $9FA980 ; sold out item org $96F9BA ; properties DB $00,$00,$00,$10,$00,$00,$00,$00,$00,$00,$00,$00,$00 org $9EDD6C ; name DB "SOLD OUT " ; overwrites "Crown " org $D08000 ; signature, start of expanded data area DB "ArchipelagoLufia" org $D09800 ; start of expanded code area ; initialize pushpc org $808046 ; DB=$80, x=1, m=1 JSL Init ; overwrites JSL $809037 pullpc Init: ; check signature LDX.b #$0F -: LDA $D08000,X CMP $F02000,X BNE + DEX BPL - BRA ++ ; set up DMA to clear expanded SRAM +: STZ $211C ; force multiplication results (MPYx) to zero REP #$10 LDA.b #$80 STA $4300 ; transfer B-bus to A-bus, with A-bus increment LDA.b #$34 STA $4301 ; B-bus source register $2134 (MPYL) LDX.w #$2000 STX $4302 ; A-bus destination address $F02000 (SRAM) LDA.b #$F0 STA $4304 LDX.w #$6000 STX $4305 ; transfer 24kB LDA.b #$01 STA $420B ; start DMA channel 1 ; sign expanded SRAM PHB TDC LDA.b #$3F LDX.w #$8000 LDY.w #$2000 MVN $F0,$D0 ; copy 64B from $D08000 to $F02000 PLB ++: SEP #$30 JSL $809037 ; (overwritten instruction) RTL ; transmit checks from chests pushpc org $8EC1EB JML TX ; overwrites JSL $83F559 pullpc TX: JSL $83F559 ; (overwritten instruction) chest opening animation REP #$20 LDA $7FD4EF ; read chest item ID BIT.w #$0200 ; test for iris item flag BEQ + JSR ReportLocationCheck SEP #$20 JML $8EC2DC ; skip item get process; consider chest emptied +: BIT.w #$4200 ; test for blue chest flag BEQ + LDA $F02048 ; load total blue chests checked CMP $D08010 ; compare against max AP item number BPL + LDA $F02040 ; load check counter INC ; increment check counter STA $F02040 ; store check counter SEP #$20 JML $8EC2DC ; skip item get process; consider chest emptied +: SEP #$20 JML $8EC1EF ; continue item get process ; transmit checks from script events pushpc org $80A435 ; DB=$8E, x=0, m=1 JML ScriptTX ; overwrites STA $7FD4F1 pullpc ScriptTX: STA $7FD4F1 ; (overwritten instruction) LDA $05AC ; load map number CMP.b #$F1 ; check if ancient cave final floor BNE + REP #$20 LDA $7FD4EF ; read script item id CMP.w #$01C2 ; test for ancient key BNE + JSR ReportLocationCheck SEP #$20 JML $80A47F ; skip item get process +: SEP #$20 JML $80A439 ; continue item get process ReportLocationCheck: PHA ; remember item id LDA $F0204A ; load other locations count INC ; increment check counter STA $F0204A ; store other locations count DEC ASL TAX PLA STA $F02060,X ; store item id in checked locations list RTS ; report event flag based goal completion Goal: TDC LDA $0797 ; load EV flags $C8-$CF (iris sword, iris shield, ..., iris pot) TAX LDA $0798 ; load EV flags $D0-$D7 (iris tiara, boss, others...) TAY AND.b #$02 ; test boss victory LSR STA $F02031 ; report boss victory goal TYA AND.b #$01 ; test iris tiara ADC $97B418,X ; test remaining iris items via predefined lookup table for number of bits set in a byte CMP $D08017 ; compare with number of treasures required BMI + LDA.b #$01 STA $F02032 ; report iris treasures goal AND $F02031 STA $F02033 ; report boss victory + iris treasures goal +: RTS ; receive items RX: REP #$20 LDA $F02802 ; load snes side received items processed counter CMP $F02800 ; compare with client side received items counter BPL + INC STA $F02802 ; increase received items processed counter ASL TAX LDA $F02802,X ; load received item ID BRA ++ +: LDA $F02046 ; load snes side found AP items processed counter CMP $F02044 ; compare with client side found AP items counter BPL + LDA $F02044 STA $F02046 ; increase AP items processed counter LDA.w #$01CA ; load "AP item" ID ++: STA $7FD4EF ; store it as a "chest" JSR SpecialItemGet SEP #$20 JSL $8EC1EF ; call chest opening routine (but without chest opening animation) STZ $A7 ; cleanup JSL $83AB4F ; cleanup +: SEP #$20 RTS SpecialItemGet: BPL + ; spells have high bit set JSR LearnSpell +: BIT.w #$0200 ; iris items BEQ + SEC SBC.w #$039C ASL TAX LDA $8ED8C3,X ; load predefined bitmask with a single bit set ORA $0797 STA $0797 ; set iris item EV flag ($C8-$D0) BRA ++ +: CMP.w #$01C2 ; ancient key BNE + LDA.w #$0008 ORA $0796 STA $0796 ; set ancient key EV flag ($C3) LDA.w #$0200 ORA $0797 STA $0797 ; set boss item EV flag ($D1) BRA ++ +: CMP.w #$01BF ; capsule monster items range from $01B8 to $01BE BPL ++ SBC.w #$01B1 ; party member items range from $01B2 to $01B7 BMI ++ ASL TAX LDA $8ED8C7,X ; load predefined bitmask with a single bit set ORA $F02018 ; set unlock bit for party member/capsule monster STA $F02018 ++: RTS LearnSpell: STA $0A0B SEP #$20 LDA.b #$06 -: PHA JSL $82FD3D ; teach spell in $0A0B to character determined by A PLA DEC BPL - REP #$20 LDA $0A0B RTS ; use items pushpc org $82AE6F ; DB=$83, x=0, m=1 JSL SpecialItemUse ; overwrites JSL $81EFDF org $8EFD2E ; unused region at the end of bank $8E DB $1E,$0B,$01,$2B,$01,$1A,$02,$00 ; add selan DB $1E,$0B,$01,$2B,$02,$1A,$03,$00 ; add guy DB $1E,$0B,$01,$2B,$03,$1A,$04,$00 ; add arty DB $1E,$0B,$01,$2B,$05,$1A,$05,$00 ; add dekar DB $1E,$0B,$01,$2B,$04,$1A,$06,$00 ; add tia DB $1E,$0B,$01,$2B,$06,$1A,$07,$00 ; add lexis DB $1F,$0B,$01,$2C,$01,$1B,$02,$00 ; remove selan DB $1F,$0B,$01,$2C,$02,$1B,$03,$00 ; remove guy DB $1F,$0B,$01,$2C,$03,$1B,$04,$00 ; remove arty DB $1F,$0B,$01,$2C,$05,$1B,$05,$00 ; remove dekar DB $1F,$0B,$01,$2C,$04,$1B,$06,$00 ; remove tia DB $1F,$0B,$01,$2C,$06,$1B,$07,$00 ; remove lexis pullpc SpecialItemUse: JSL $81EFDF ; (overwritten instruction) REP #$20 LDA $0A06 ; get ID of item being used CMP.w #$01B8 BPL + SBC.w #$01B1 ; party member items range from $01B2 to $01B7 BMI + ASL TAX ASL ASL ADC.w #$FD2E STA $09B7 ; set pointer to L2SASM join script SEP #$20 LDA $8ED8C7,X ; load predefined bitmask with a single bit set BIT $077E ; check against EV flags $02 to $07 (party member flags) BEQ ++ LDA.b #$30 ; character already present; modify pointer to point to L2SASM leave script ADC $09B7 STA $09B7 BRA +++ ++: LDA $07A9 ; character not present; load EV register $0B (party counter) CMP.b #$03 BPL + ; abort if party full +++ LDA.b #$8E STA $09B9 PHK PEA ++ PEA $8DD8 JML $83BB76 ; initialize parser variables ++: NOP JSL $809CB8 ; call L2SASM parser TSX INX #13 TXS JML $82A45E ; leave menu +: SEP #$20 RTL ; main loop pushpc org $83BC16 ; DB=$83, x=0, m=1 JSL MainLoop ; overwrites LDA $09A7 : BIT.b #$01 NOP pullpc MainLoop: JSR RX JSR Goal JSR Unlocks LDA $09A7 ; (overwritten instruction) BIT.b #$01 ; (overwritten instruction) RTL Unlocks: LDA $F02018 ; load party member unlocks from SRAM STA $0780 ; transfer to flags (WRAM) LDA $F02019 ; load capsule monster unlocks from SRAM TAY LDX.w #$0000 -: TYA LSR TAY BCC + LDA $82C33C CMP $11BB,X BMI +++ BRA ++ +: LDA.b #$00 ++: STA $11BB,X ; unlock/lock capsule monster #X +++ INX CPX.w #$0007 BNE - LDA $F02019 TAY BNE + LDA.b #$FF STA $0A7F ; lock capsule menu BRA ++ +: LDA.b #$07 STA $0A7F ; unlock capsule menu LDA $F02019 BIT.b #$80 ; track whether one-time setup has been done before BNE ++ ORA.b #$80 STA $F02019 CMP.b #$FF BEQ ++ ; all capsule monsters available; don't overwrite starting capsule LDX.w #$FFFF TYA -: LSR INX BCC - TXA STA $11A3 ; activate first unlocked capsule monster STA $7FB5FB STA $F02016 JSL $82C2FD ; run setup routine for capsule monsters ++: RTS ; lock party members pushpc org $8AEC3E DB $15,$C4,$A4,$01 ; L2SASM JMP $8AEB1C+$01A4 if flag $C4 set org $8AECC0 DB $6C,$65,$00,$FA ; (overwritten instruction) DB $15,$12,$AE,$01,$2E,$66 ; remove selan if flag $12 clear DB $15,$13,$B4,$01,$2E,$67 ; remove guy if flag $13 clear DB $15,$14,$BA,$01,$2E,$68 ; remove arty if flag $14 clear DB $15,$15,$C0,$01,$2E,$6A ; remove dekar if flag $15 clear DB $15,$16,$C6,$01,$2E,$69 ; remove tia if flag $16 clear DB $15,$17,$CC,$01,$2E,$6B ; remove lexis if flag $17 clear DB $00 pullpc ; party member items (IDs $01B2 - $01B7) pushpc org $96F875 ; properties DB $40,$00,$00,$E9,$64,$00,$00,$00,$00,$00,$00,$00,$00 DB $40,$00,$00,$E0,$64,$00,$00,$00,$00,$00,$00,$00,$00 DB $40,$00,$00,$EB,$64,$00,$00,$00,$00,$00,$00,$00,$00 DB $40,$00,$00,$ED,$64,$00,$00,$00,$00,$00,$00,$00,$00 DB $40,$00,$00,$E8,$64,$00,$00,$00,$00,$00,$00,$00,$00 DB $40,$00,$00,$EF,$64,$00,$00,$00,$00,$00,$00,$00,$00 org $979EC6 ; descriptions DB "Parcelyte commander. " : DB $00 DB "A guy named Guy. " : DB $00 DB "(Or was it Artea?) " : DB $00 DB "Strongest warrior. " : DB $00 DB "Elcid shopkeeper. " : DB $00 DB "Great inventor." : DB $00 org $97FDAC ; remove from scenario item list DW $0000,$0000,$0000,$0000,$0000,$0000 org $9EDC40 ; names DB "Selan " ; overwrites "Wind key " DB "Guy " ; overwrites "Cloud key " DB "Arty " ; overwrites "Light key " DB "Dekar " ; overwrites "Sword key " DB "Tia " ; overwrites "Tree key " DB "Lexis " ; overwrites "Flower key " pullpc ; capsule monster items (IDs $01B8 - $01BE) pushpc org $96F8C3 ; properties DB $00,$00,$00,$EE,$12,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$EE,$12,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$EE,$12,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$EE,$12,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$EE,$12,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$EE,$12,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$00,$00,$EE,$12,$00,$00,$00,$00,$00,$00,$00,$00 org $979F47 ; descriptions DB "NEUTRAL " : DB $00 DB "LIGHT " : DB $00 DB "WIND " : DB $00 DB "WATER " : DB $00 DB "DARK " : DB $00 DB "SOIL " : DB $00 DB "FIRE " : DB $00 org $9EDC88 ; names DB "JELZE " ; overwrites "Magma key " DB "FLASH " ; overwrites "Heart key " DB "GUSTO " ; overwrites "Ghost key " DB "ZEPPY " ; overwrites "Trial key " DB "DARBI " ; overwrites "Dankirk key " DB "SULLY " ; overwrites "Basement key" DB "BLAZE " ; overwrites "Narcysus key" pullpc ; allow inactive characters to gain exp pushpc org $81DADD ; DB=$81, x=0, m=1 NOP ; overwrites BNE $81DAE2 : JMP $DBED JML HandleActiveExp AwardExp: ; isolate exp distribution into a subroutine, to be reused for both active party members and inactive characters org $81DAE9 NOP #2 ; overwrites JMP $DBBD RTL org $81DB42 NOP #2 ; overwrites JMP $DBBD RTL org $81DD11 ; DB=$81, x=0, m=1 JSL HandleInactiveExp ; overwrites LDA $0A8A : CLC pullpc HandleActiveExp: BNE + ; (overwritten instruction; modified) check if statblock not empty JML $81DBED ; (overwritten instruction; modified) abort +: JSL AwardExp ; award exp (X=statblock pointer, Y=position in battle order, $00=position in menu order) JML $81DBBD ; (overwritten instruction; modified) continue to next level text HandleInactiveExp: LDA $F0201B ; load inactive exp gain rate BEQ + ; zero gain; skip everything CMP.b #$64 BCS ++ ; full gain LSR $1607 ROR $1606 ; half gain ROR $1605 ++: LDY.w #$0000 ; start looping through all characters -: TDC TYA LDX.w #$0003 ; start looping through active party --: CMP $0A7B,X BEQ ++ ; skip if character in active party DEX BPL -- ; continue looping through active party STA $153D ; inactive character detected; overwrite character index of 1st slot in party battle order ASL TAX REP #$20 LDA $859EBA,X ; convert character index to statblock pointer SEP #$20 TAX PHY ; stash character loop index LDY $0A80 PHY ; stash 1st (in menu order) party member statblock pointer STX $0A80 ; overwrite 1st (in menu order) party member statblock pointer LDY.w #$0000 ; set to use 1st position (in battle order) STY $00 ; set to use 1st position (in menu order) JSL AwardExp ; award exp (X=statblock pointer, Y=position in battle order, $00=position in menu order) PLY ; restore 1st (in menu order) party member statblock pointer STY $0A80 PLY ; restore character loop index ++: INY CPY.w #$0007 BCC - ; continue looping through all characters +: LDA $0A8A ; (overwritten instruction) load current gold CLC ; (overwritten instruction) RTL ; receive death link pushpc org $83BC91 ; DB=$83, x=0, m=1 JSL DeathLinkRX ; overwrites LDA $7FD0AE pullpc DeathLinkRX: LDA $F0203F ; check death link trigger BEQ + TDC STA $F0203F ; reset death link trigger LDA $F0203D ; check death link enabled BEQ + LDA.b #$04 STA $0BBC ; kill maxim STA $0C7A ; kill selan STA $0D38 ; kill guy STA $0DF6 ; kill arty STA $0EB4 ; kill tia STA $0F72 ; kill dekar STA $1030 ; kill lexis LDA.b #$FE STA $7FF8A3 ; select normal enemy battle LDA.b #$82 STA $7FF8A4 ; select a formation containing only demise JSL $8383EB ; force battle +: LDA $7FD0AE ; (overwritten instruction) RTL DeathLinkTX: LDA $F0203D ; check death link enabled BEQ + LDA $7FF8A4 ; load formation number CMP.b #$82 ; did we die from a death link? BEQ + STA $004202 LDA.b #$0A STA $004203 ; multiply by 10 to get formation offset TDC NOP LDA $004216 TAX LDA $7FF756,X ; read first monster in formation INC STA $F0203E ; send death link by monster id + 1 +: RTL ; clear receiving counters when starting new game; force "GIFT" mode pushpc org $83AD83 ; DB=$83, x=0, m=1 JSL ClearRX ; overwrites BIT #$02 : BEQ $83ADAB pullpc ClearRX: REP #$20 TDC STA $F02800 ; clear received count STA $F02802 ; clear processed count SEP #$20 ; absence of the overwritten instructions automatically leads to "GIFT" mode code path RTL ; store receiving counters when saving game pushpc org $82EB61 ; DB=$8A, x=0, m=1 JSL SaveRX ; overwrites JSL $8090C9 pullpc SaveRX: JSL $8090C9 ; (overwritten instruction) write save slot A to SRAM SEP #$10 REP #$20 ASL ASL TAX LDA $F02800 ; STA $F027E0,X ; save received count LDA $F02802 ; STA $F027E2,X ; save processed count SEP #$20 REP #$10 RTL ; restore receiving counters when loading game pushpc org $82EAD5 ; DB=$83, x=0, m=1 JSL LoadRX ; overwrites JSL $809099 pullpc LoadRX: JSL $809099 ; (overwritten instruction) load save slot A from SRAM SEP #$10 REP #$20 ASL ASL TAX LDA $F027E0,X ; STA $F02800 ; restore received count LDA $F027E2,X ; STA $F02802 ; restore processed count SEP #$20 REP #$10 RTL ; keep inventory after defeat pushpc org $848B9C ; DB=$7E, x=0, m=1 NOP #5 ; overwrites LDA.b #$FF : STA $7FE759 : JSR $8888 JSL DeathLinkTX pullpc ; set initial floor number pushpc org $8487A9 JSL InitialFloor ; overwrites TDC : STA $7FE696 NOP pullpc InitialFloor: LDA $D08015 ; read initial floor number STA $7FE696 ; (overwritten instruction) TDC ; (overwritten instruction) RTL ; report final floor goal completion pushpc org $839E87 JSL FinalFloor ; overwrites STA $0005B0 pullpc FinalFloor: STA $0005B0 ; (overwritten instruction) LDA.b #$01 STA $F02034 ; report final floor goal RTL ; start with Providence pushpc org $8488BB ; DB=$84, x=0, m=0 JSL Providence ; overwrites LDX.w #$1402 : STX $0A8D NOP #2 pullpc Providence: LDX.w #$1402 ; (overwritten instruction) STX $0A8D ; (overwritten instruction) add Potion x10 LDX.w #$022D STX $0A8F ; add Providence RTL ; start inventory pushpc org $848901 ; DB=$84, x=0, m=1 JSL StartInventory ; overwrites JSL $81ED35 pullpc StartInventory: JSL $81ED35 ; (overwritten instruction) REP #$20 LDA $F02802 ; number of items to process DEC BMI ++ ; skip if empty ASL TAX -: LDA $F02804,X ; item ID BPL + ; spells have high bit set PHX JSR LearnSpell PLX +: BIT.w #$C200 ; ignore spells, blue chest items, and iris items BNE + PHX STA $09CF ; specify item ID TDC INC STA $09CD ; specify quantity as 1 JSL $82E80C ; add item to inventory REP #$20 PLX +: DEX DEX BPL - ++: SEP #$20 RTL ; architect mode pushpc org $8EA1E7 base = $8EA1AD ; ancient cave entrance script base DB $15,$E1 : DW .locked-base ; L2SASM JMP .locked if flag $E1 set DB $08,"Did you like the layout",$03, \ "of the last cave? I can",$03, \ "lock it down and prevent",$03, \ "the cave from changing.",$01 DB $08,"Do you want to lock",$03, \ "the cave layout?",$01 DB $10,$02 : DW .cancel-base,.lock-base ; setup 2 choices: .cancel and .lock DB $08,"Cancel",$0F,"LOCK IT DOWN!",$0B .cancel: DB $4C,$54,$00 ; play sound $54, END .lock: DB $5A,$05,$03,$7F,$37,$28,$56,$4C,$6B,$1A,$E1 ; shake, delay $28 f, stop shake, play sound $6B, set flag $E1 .locked: DB $08,"It's locked down.",$00 warnpc $8EA344 org $839018 ; DB=$83, x=0, m=1 JSL ArchitectMode ; overwrites LDA.b #$7E : PHA : PLB pullpc ArchitectMode: ; check current mode LDA $079A BIT.b #$02 BEQ + ; go to write mode if flag $E1 (i.e., bit $02 in $079A) not set ; read mode (replaying the locked down layout) JSR ArchitectBlockAddress LDA $F00000,X ; check if current block is marked as filled BEQ + ; go to write mode if block unused TDC LDA.b #$36 LDY.w #$0521 INX MVN $7E,$F0 ; restore 55 RNG values from $F00000,X to $7E0521 INX LDA $F00000,X STA $0559 ; restore current RNG index from $F00000,X to $7E0559 BRA ++ ; write mode (recording the layout) +: JSR ArchitectClearBlocks JSR ArchitectBlockAddress LDA $7FE696 STA $F00000,X ; mark block as used TDC LDA.b #$36 LDX.w #$0521 INY MVN $F0,$7E ; backup 55 RNG values from $7E0521 to $F00000,Y INY LDA $7E0559 STA $0000,Y ; backup current RNG index from $7E0559 to $F00000,Y LDA.b #$7E ; (overwritten instruction) set DB=$7E PHA ; (overwritten instruction) PLB ; (overwritten instruction) ++: RTL ArchitectClearBlocks: LDA $7FE696 ; read next floor number CMP $D08015 ; compare initial floor number BEQ + BRL ++ ; skip if not initial floor +: LDA.b #$F0 PHA PLB !floor = 1 while !floor < 99 ; mark all blocks as unused STZ !floor*$40+$6000 !floor #= !floor+1 endwhile ++: RTS ArchitectBlockAddress: ; calculate target SRAM address TDC LDA $7FE696 ; read next floor number REP #$20 ASL #6 ADC.w #$6000 ; target SRAM address = next_floor * $40 + $6000 TAX TAY SEP #$20 RTS ; for architect mode: make red chest behavior for iris treasure replacements independent of current inventory ; by ensuring the same number of RNG calls, no matter if you have the iris item already or not ; (done by prefilling *all* chests first and potentially overwriting one of them with an iris item afterwards, ; instead of checking the iris item first and then potentially filling *one fewer* regular chest) pushpc org $8390C9 ; DB=$96, x=0, m=1 NOP ; overwrites LDY.w #$0000 BRA + ; go to regular red chest generation -: ; iris treasure handling happens below org $839114 ; DB=$7F, x=0, m=1 NOP #36 ; overwrites all of providence handling LDA.b #$83 ; (overwritten instruction from org $8391E9) set DB=$83 for floor layout generation PHA ; (overwritten instruction from org $8391E9) PLB ; (overwritten instruction from org $8391E9) BRL ++ ; go to end +: LDY.w #$0000 ; (overwritten instruction from org $8390C9) initialize chest index ; red chests are filled below org $8391E9 ; DB=$7F, x=0, m=1 NOP ; overwrites LDA.b #$83 : PHA : PLB BRL - ; go to iris treasure handling ++: ; floor layout generation happens below pullpc ; for architect mode: make red chest behavior for spell replacements independent of currently learned spells ; by ensuring the same number of RNG calls, no matter if you have the spell already or not pushpc org $8391A6 ; DB=$7F, x=0, m=1 JSL SpellRNG ; overwrites LDA.b #$80 : STA $E747,Y NOP pullpc SpellRNG: LDA.b #$80 ; (overwritten instruction) mark chest item as spell STA $E747,Y ; (overwritten instruction) JSL $8082C7 ; JSL $8082C7 ; advance RNG twice RTL ; shops pushpc org $83B442 ; DB=$83, x=1, m=1 JSL Shop ; overwrites STA $7FD0BF pullpc Shop: STA $7FD0BF ; (overwritten instruction) LDY $05AC ; load map number CPY.b #$F0 ; check if ancient cave BCC + LDA $05B4 ; check if going to ancient cave entrance BEQ + LDA $7FE696 ; load next to next floor number DEC CPY.b #$F1 ; check if going to final floor BCS ++ ; skip a decrement because next floor number is not incremented on final floor DEC ++: CMP $D08015 ; check if past initial floor BCC + STA $4204 ; WRDIVL; dividend = floor number STZ $4205 ; WRDIVH TAX LDA $D0801A STA $4206 ; WRDIVB; divisor = shop_interval STA $211C ; M7B; second factor = shop_interval JSL $8082C7 ; advance RNG (while waiting for division to complete) LDY $4216 ; RDMPYL; skip if remainder (i.e., floor number mod shop_interval) is not 0 BNE + STA $211B STZ $211B ; M7A; first factor = random number from 0 to 255 TXA CLC SBC $2135 ; MPYM; calculate (floor number) - (random number from 0 to shop_interval-1) - 1 STA $30 ; set shop id STZ $05A8 ; initialize variable for sold out item tracking STZ $05A9 PHB PHP JML $80A33A ; open shop menu (eventually causes return by reaching existing PLP : PLB : RTL at $809DB0) +: RTL ; shop item select pushpc org $82DF50 ; DB=$83, x=0, m=1 JML ShopItemSelected ; overwrites JSR $8B08 : CMP.b #$01 pullpc ShopItemSelected: LDA $1548 ; check inventory free space BEQ + JSR LoadShopSlotAsFlag BIT $05A8 ; test item not already sold BNE + JML $82DF79 ; skip quantity selection and go directly to buy/equip +: JML $82DF80 ; abort and go back to item selection ; track bought shop items pushpc org $82E084 ; DB=$83, x=0, m=1 JSL ShopBuy ; overwrites LDA.b #$05 : LDX.w #$0007 NOP org $82E10E ; DB=$83, x=0, m=1 JSL ShopEquip ; overwrites SEP #$10 : LDX $14DC NOP pullpc ShopBuy: JSR LoadShopSlotAsFlag TSB $05A8 ; mark item as sold LDA.b #$05 ; (overwritten instruction) LDX.w #$0007 ; (overwritten instruction) RTL ShopEquip: JSR LoadShopSlotAsFlag TSB $05A8 ; mark item as sold SEP #$10 ; (overwritten instruction) LDX $14DC ; (overwritten instruction) RTL LoadShopSlotAsFlag: TDC LDA $14EC ; load currently selected shop slot number ASL TAX LDA $8ED8C3,X ; load predefined bitmask with a single bit set RTS ; mark bought items as sold out pushpc org $8285EA ; DB=$83, x=0, m=0 JSL SoldOut ; overwrites LDA [$FC],Y : AND #$01FF NOP pullpc SoldOut: LDA $8ED8C3,X ; load predefined bitmask with a single bit set BIT $05A8 ; test sold items BEQ + LDA.w #$01CB ; load sold out item id BRA ++ +: LDA [$FC],Y ; (overwritten instruction) AND #$01FF ; (overwritten instruction) ++: RTL ; increase variety of red chest gear after B9 pushpc org $839176 ; DB=$7F, x=0, m=1 CLC ; {carry clear = disable this feature, carry set = enable this feature} JSL RedChestGear ; overwrites LDX.w #$1000 : LDA $60 org $83917D ; DB=$7F, x=0, m=1 JSL RunEquipmentRNG ; overwrites LSR : JSR $9E11 pullpc RedChestGear: BCC + REP #$20 ; support more than 127 items +: LDX.w #$1000 ; (overwritten instruction) LDA $60 ; (overwritten instruction) RTL RunEquipmentRNG: BCS + SEP #$20 PHK PEA ++ PEA $8DD8 LSR JML $839E11 +: LSR ; (overwritten instruction) divide by 2 (translates max item offset to max item number) SEP #$20 ; (the max item number fits in 8bits since there are always fewer than 256 eligible items) STA $004202 ; run RNG: fill WRMPYA multiplicand register with max item number JSL $8082C7 ; run RNG: load 8bit accumulator with 1st random number from PRNG STA $004203 ; run RNG: fill WRMPYB multiplier register with 1st random number and start multiplication NOP REP #$20 LDA $004216 ; run RNG: read RDMPYL+H multiplication result STA $E746,Y ; save it for later SEP #$20 JSL $8082C7 ; run RNG: load 8bit accumulator with 2nd random number from PRNG STA $004203 ; run RNG: fill WRMPYB multiplier register with 2nd random number and start multiplication CLC TDC LDA $004217 ; run RNG: read RDMPYH multiplication result REP #$20 ADC $E746,Y AND.w #$FF00 XBA ASL ; multiply by 2 (translates selected item number to selected item offset) ++: TAX ; store result in 16bit X register RTL ; relocate capsule cravings table pushpc org $82C55A LDA $D09200,X ; overwrites LDA $95FF16,X org $82C55F LDA $D09202,X ; overwrites LDA $95FF18,X org $82C572 LDA $D09200,X ; overwrites LDA $95FF16,X pullpc ; set capsule monster starting xp pushpc org $82C313 ; DB=$84, x=0, m=1 JSL CapsuleStartingXp ; overwrites LDX.w #$0000 : LDA.b #$00 : STA $7FF1AA,X : INX : CPX.w #$0015 : BNE $82C318 NOP #11 pullpc CapsuleStartingXp: PHB REP #$20 LDA $D08012 STA $7FF1AA ; store low word of starting XP for first capsule monster SEP #$20 LDA $D08014 STA $7FF1AC ; store highest byte of starting XP for first capsule monster TDC LDA.b #$11 LDX.w #$F1AA LDY.w #$F1AD MVN $7F,$7F ; pattern fill the remaining six capsule monster slots PLB RTL ; set starting capsule monster pushpc org $82C36A ; DB=$83, x=0, m=1 JSL StartingCapsule ; overwrites STZ $11A3 : LDA.b #$01 NOP pullpc StartingCapsule: LDA $F02016 ; read starting capsule monster id STA $11A3 LDA.b #$01 ; (overwritten instruction) RTL ; enter ancient cave as if coming from the world map pushpc org $83B773 ; DB=$7E, x=0, m=1 JSL CaveEntrance ; overwrites LDA $05AC : STA $05B4 NOP #2 pullpc CaveEntrance: LDA $05AC ; (overwritten instruction) CMP.b #$68 BNE + ; when leaving gruberik, act as if leaving world map TDC +: STA $05B4 ; (overwritten instruction) RTL ; enable run button ; directional input item crash fix pushpc org $83FC6C REP #$10 ; overwrites BEQ $83FC8A : LDA.b #$80 LDA.b #$40 pullpc ; mid-turn death fix pushpc org $85B544 JSL MidTurnDeathFix ; overwrites JSL $85CCCE pullpc MidTurnDeathFix: JSL $85CCCE ; (overwritten instruction) clear shared battle registers after attack LDY.w #$000F ; offset to status effect byte LDA ($BE),Y ; offset to stat block of attacker BIT.b #$04 ; check death BEQ + TSX ; attacker died; abort script INX #3 TXS JML $85B476 +: RTL ; attacker still alive; continue script ; poison death fix pushpc org $818959 JSL PoisonDeathFix ; overwrites JSL $859DD4 pullpc PoisonDeathFix: JSL $859DD4 ; (overwritten instruction) JSL $8593B7 RTL ; single-node room fix pushpc org $839C64 ; DB=$7F, x=0, m=1 BNE + ; overwrites BNE $17 org $839C7B ; DB=$7F, x=0, m=1 JMP $9BE7 ; overwrites BRA $22 : LDX.w #$00FF +: TDC TAX org $839C99 ; DB=$7F, x=0, m=1 INX ; overwrites DEX : CPX.w #$0010 : BCS $E1 CPX.w #$0100 BCC $E1 pullpc ; door stairs fix pushpc org $839453 ; DB=$7F, x=0, m=1 JSL DoorStairsFix ; overwrites JSR $9B18 : JSR $9D11 NOP #2 pullpc DoorStairsFix: CLC LDY.w #$0000 --: LDX.w #$00FF ; loop through floor layout starting from the bottom right -: LDA $EA00,X ; read node contents BEQ + ; always skip empty nodes BCC ++ ; 1st pass: skip all blocked nodes (would cause door stairs or rare stairs) LDA $E9F0,X ; 2nd pass: skip only if the one above is also blocked (would cause door stairs) ++: BMI + INY ; count usable nodes +: DEX BPL - TYA BNE ++ ; all nodes blocked? SEC ; set up 2nd, less restrictive pass BRA -- ++: JSL $8082C7 ; advance RNG STA $00211B TDC STA $00211B ; M7A; first factor = random number from 0 to 255 TYA STA $00211C ; M7B; second factor = number of possible stair positions LDA $002135 ; MPYM; calculate random number from 0 to number of possible stair positions - 1 TAY LDX.w #$00FF ; loop through floor layout starting from the bottom right -: LDA $EA00,X ; read node contents BEQ + ; always skip empty nodes BCC ++ ; if 1st pass was sufficient: skip all blocked nodes (prevent door stairs and rare stairs) LDA $E9F0,X ; if 2nd pass was needed: skip only if the one above is also blocked (prevent door stairs) ++: BMI + DEY ; count down to locate the (Y+1)th usable node BMI ++ +: DEX BPL - ++: TXA ; return selected stair node coordinate RTL ; equipment text fix pushpc org $81F2E3 ; DB=$9E, x=0, m=1 NOP #2 ; overwrites BPL $81F2D6 pullpc ; music menu fix pushpc org $82BF44 ; DB=$83, x=0, m=1 BNE $12 ; overwrites BNE $06 pullpc ; logo skip pushpc org $80929A ; DB=$80, x=0, m=1 LDA.b #$00 ; overwrites LDA.b #$80 pullpc ; intro skip pushpc org $8080CF ; DB=$80, x=1, m=1 JML $8383BD ; overwrites JML $808281 pullpc ; SRAM map ; $F02000 16 signature ; $F02010 2 blue chest count ; $F02012 3 capsule starting xp ; $F02015 1 initial floor ; $F02016 1 starting capsule ; $F02017 1 iris treasures required ; $F02018 1 party members available ; $F02019 1 capsule monsters available ; $F0201A 1 shop interval ; $F0201B 1 inactive exp gain rate ; $F02030 1 selected goal ; $F02031 1 goal completion: boss ; $F02032 1 goal completion: iris_treasure_hunt ; $F02033 1 goal completion: master_iris_treasure_hunt ; $F02034 1 goal completion: final_floor ; $F0203D 1 death link enabled ; $F0203E 1 death link sent (monster id + 1) ; $F0203F 1 death link received ; $F02040 2 check counter for this save file (snes_blue_chests_checked) ; $F02042 2 RESERVED ; $F02044 2 check counter (client_ap_items_found) ; $F02046 2 check counter (snes_ap_items_found) ; $F02048 2 check counter for the slot (total_blue_chests_checked) ; $F0204A 2 check counter for this save file (snes_other_locations_checked) ; $F02050 16 coop uuid ; $F02060 var list of checked locations ; $F027E0 16 saved RX counters ; $F02800 2 received counter ; $F02802 2 processed counter ; $F02804 var list of received items ; $F06000 var architect mode RNG state backups