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
