; hooks org $81E6B0 JSL RevealPotItem RTS org $829C25 JSL SetTheSceneFix org $89C2BB JSL ClearSpriteData ; underworld -> overworld transition org $8282D1 JSL ClearSpriteData2 org $89C327 JSL LoadSpriteData org $86F976 JSL RevealSpriteDrop : NOP org $86E3C4 JSL RevealSpriteDrop2 : NOP org $86926e ; <- 3126e - sprite_prep.asm : 2664 (LDA $0B9B : STA $0CBA, X) JSL SpriteKeyPrep : NOP #2 org $86d049 ; <- 35049 sprite_absorbable : 31-32 (JSL Sprite_DrawRippleIfInWater : JSR Sprite_DrawAbsorbable) JSL SpriteKeyDrawGFX : BRA + : NOP : + org $86d03d JSL ShouldSpawnItem : NOP #2 org $86D19F JSL MarkSRAMForItem : NOP #2 org $86d180 JSL BigKeyGet : BCS $07 : NOP #5 org $86d18d ; <- 3518D - sprite_absorbable.asm : 274 (LDA $7EF36F : INC A : STA $7EF36F) JSL KeyGet org $86f9f3 ; bank06.asm : 6732 (JSL Sprite_LoadProperties) JSL LoadProperties_PreserveCertainProps ;org $808BAA ; NMI hook ; JSL TransferPotGFX org $86828A JSL CheckSprite_Spawn org $87B169 JSL PreventPotSpawn : NOP org $87B17D JSL PreventPotSpawn2 org $868275 JSL SubstitionFlow org $80A9DC dw $1928, $1938, $5928, $5938 ; change weird ugly black diagonal pot to blue-ish pot org $818650 dw $B395 ; change tile type to normal pot org $81B3D5 JSL CheckIfPotIsSpecial ; refs to other functions org $8681F4 Sprite_SpawnSecret_pool_ID: org $868283 Sprite_SpawnSecret_NotRandomBush: org $86828A Sprite_SpawnSecret_SpriteSpawnDynamically: org $86d23a Sprite_DrawAbsorbable: org $9eff81 Sprite_DrawRippleIfInWater: org $8db818 Sprite_LoadProperties: org $86D038 KeyRoomFlagMasks: org $80FDEE InitializeMirrorHDMA: org $80E3C4 LoadCommonSprites_long: org $09D62E UWSpritesPointers: ; 0x250 bytes for 0x128 rooms' 16-bit pointers org $09D87E UWPotsPointers: ; 0x250 bytes for 0x128 rooms' 16-bit pointers org $09DACE UWPotsData: ; variable number of bytes (max 0x11D1) for all pots data org $A88000 UWSpritesData: ; variable number of bytes (max 0x2800) for all sprites and sprite drop data ; First $2800 bytes of this bank (28) is reserved for the sprite tables ; $2800 bytes reserved for sprites org $A8A800 ;tables: PotMultiWorldTable: ; Reserved $250 296 * 2 org $A8AA50 StandingItemsOn: ; 142A50 db 0 MultiClientFlagsROM: ; 142A51-2 -> stored in SRAM at 7ef33d (for now) dw 0 SwampDrain1HasItem: ; 142A53 db 1 SwampDrain2HasItem: ; 142A54 db 1 StandingItemCounterMask: ; 142A55 db 0 ; if 0x01 is set then pot should be counted, if 0x02 then sprite drops, 0x03 (both bits for both) PotCountMode: ; 28AA56-7 ; 0 is don't count pots ; 1 for check PotCollectionRateTable dw 0 org $A8AA60 PotCollectionRateTable: ; Reserved $250 296 * 2 org $A8ACB0 UWEnemyItemFlags: ; Reserved $250 296 * 2 org $A8AF00 UWSpecialFlagIndex: ; Reserved $128 (296) ; Initial table indexed by room id ; Special values: $FF indicates the room can use the UWEnemyItemFlags table ; Any other value tell you where to start in the special table db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF db $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF org $A8B028 UWSpecialFlag: ; reserved exactly $100 or 256 bytes for now estimated usage is at 159 bytes right now ; Simple mask table, 3 bytes per entry: 1st byte what dungeon it applies, if $FF, then the list is done ; Lists that has even numbers of entries will end with $FF $FF to keep everything 2 byte aligned ; (if not matched, assume mask of value 0) ; 2nd and 3rd bytes are the mask ; For indicator idea: ; EOR between a mask and the equivalent SRAM should result in zero if all items are obtained ; For whether to spawn: ; $FF indicates a spawn without further checking, otherwise need to check the mask in the simple table ; this should be checked in addition to SRAM org $A8B128 RevealPotItem: STA.b $04 ; save tilemap coordinates STZ.w SpawnedItemFlag STZ.w SpawnedItemMWPlayer LDA.w $0B9C : AND.w #$FF00 : STA.w $0B9C LDA.b $A0 : ASL : TAX LDA.l UWPotsPointers,X : STA.b $00 ; we may move this LDA.w #UWPotsPointers>>16 : STA.b $02 LDY.w #$FFFD : LDX.w #$FFFF .next_pot INY : INY : INY LDA.b [$00],Y CMP.w #$FFFF : BEQ .exit INX STA.w $08 ; remember the exact value AND.w #$3FFF CMP.b $04 : BNE .next_pot ; not the correct value STZ.w SpawnedItemIsMultiWorld BIT.b $08 BVS LoadMultiWorldPotItem BMI LoadMajorPotItem .normal_secret STA $08 PHX : PHY ; set bit and count if first time lifting this pot TXA : ASL : TAX : LDA.l BitFieldMasks, X : STA $0A LDA.b $A0 : ASL : TAX JSR ShouldCountNormalPot : BCC .obtained LDA.l RoomPotData, X : BIT $0A : BNE .obtained ORA $0A : STA RoomPotData, X ; increment dungeon counts SEP #$10 LDX.w $040C : CPX.b #$FF : BEQ + CPX.b #$00 : BNE ++ INX #2 ; treat sewers as HC ++ LDA.l DungeonLocationsChecked, X : INC : STA.l DungeonLocationsChecked, X ; Could increment GT Tower Pre Big Key but we aren't showing that stat right now + REP #$10 LDA TotalItemCounter : INC : STA TotalItemCounter ; Increment Item Total INC.w UpdateHUD .obtained PLY : PLX PLA ; remove the JSL return lower 16 bits LDA $08 PEA.w $01E6E2-1 ; change return address to go back to the vanilla routine .exit RTL LoadMultiWorldPotItem: INY : INY LDA.b [$00],Y : AND.w #$00FF INC.w SpawnedItemIsMultiWorld PHX ASL : TAX LDA.l PotMultiWorldTable+1,X : AND.w #$00FF : STA.w SpawnedItemMWPlayer LDA.l PotMultiWorldTable+0,X : AND.w #$00FF PLX BRA SaveMajorItemDrop MultiItemExit: LDA.w #$0008 : STA.w $0B9C RTL LoadMajorPotItem: INY : INY LDA.b [$00],Y : AND.w #$00FF SaveMajorItemDrop: ; A currently holds the item receipt ID ; X currently holds the pot item index STA.w SpawnedItemID STX.w SpawnedItemIndex INC.w SpawnedItemFlag TAY LDA.l SpawnedItemIsMultiWorld : BNE MultiItemExit LDA.w #$0008 CPY.w #$0036 : BNE + ; Red Rupee LDA.w #$0016 : BRA .substitute + CPY.w #$0044 : BNE + ; 10 pack arrows LDA.w #$0017 : BRA .substitute + CPY.w #$0028 : BNE + ; 3 pack bombs LDA.w #$0018 : BRA .substitute + CPY.w #$0031 : BNE + ; 10 pack bombs LDA.w #$0019 : BRA .substitute + STA $0B9C ; indicates we should use the key routines or a substitute RTL .substitute PHA TXA : ASL : STA.b $00 LDA.w #$001F : SBC $00 TAX : LDA.l BitFieldMasks, X : STA $00 LDA.b $A0 : ASL : TAX LDA.l $7EF580, X AND.b $00 BNE .exit LDA.l $7EF580, X : ORA $00 : STA.l $7EF580, X PLA : STA $0B9C RTL .exit PLA : STZ.w $0B9C RTL ShouldCountNormalPot: INY : INY : LDA [$00], Y : AND #$00FF : CMP #$0080 : BCS .clear LDA.l PotCountMode : BEQ .clear LDA.l PotCollectionRateTable, X : BIT $0A : BEQ .clear ; don't count if clear .set SEC RTS .clear CLC RTS IncrementCountsForSubstitute: PHX : REP #$30 LDA.w SpawnedItemIndex : ASL : TAX : LDA.l BitFieldMasks, X : STA $0A LDA.b $A0 : ASL : TAX LDA.l RoomPotData, X : BIT $0A : BNE .obtained ORA $0A : STA RoomPotData, X SEP #$10 LDX.w $040C : CPX.b #$FF : BEQ + CPX.b #$00 : BNE ++ INX #2 ; treat sewers as HC ++ LDA.l DungeonLocationsChecked, X : INC : STA.l DungeonLocationsChecked, X ; Could increment GT Tower Pre Big Key but we aren't showing that stat right now + LDA TotalItemCounter : INC : STA TotalItemCounter ; Increment Item Total INC.w UpdateHUD .obtained SEP #$30 : PLX RTS ClearSpriteData: STZ.b $03 ; what we overrode # we no longer need STZ $02 see underworld_sprite_hooks .shared: PHX LDA #$00 : LDX #$00 .loop STA SprDropsItem, X : STA SprItemReceipt, X : STA SprItemIndex, X STA SprItemMWPlayer, X : STA SprItemFlags, X INX : CPX #$10 : BCC .loop JSR SetupEnemyDropIndicator PLX RTL ClearSpriteData2: LDA.b #$82 : STA.b $99 JMP ClearSpriteData_shared ; this routine determines whether enemies still have drops or not ; and sets EnemyDropIndicator appropriately ; uses X register, assumes flags are (MX) but (mX) is fine SetupEnemyDropIndicator: REP #$20 LDA.w #!BlankTile : STA.w !EnemyDropIndicator LDX.b $1B : BEQ .done ; do we have a flag for enemy drops on? could check it here LDA.w $040C : AND.w #$00FF : CMP.w #$00FF : BEQ .skipCompassChecks ; compass checks ; does compass for dungeon exist? LSR : TAX : LDA.l ExistsTransfer, X : TAX : LDA.l CompassExists, X : BEQ .skipCompassChecks ; doe we have the compass ; todo: sewers? LDA.l CompassField : LDX.w $040C : AND.l DungeonMask, X : BEQ .done .skipCompassChecks ; either we're in a cave ($040C: $FF), compass doesn't exist, or we have the compass ; check if there are enemy drops LDA.b $02 : PHA : REP #$10 ; store 02/03 for later LDX.b $A0 : LDA.l UWSpecialFlagIndex, X : AND.w #$00FF ; determine if special case or not CMP.w #$00FF : BEQ .loadNormalFlags JSR FetchBitmaskForSpecialCase PHA : LDA $A0 : ASL : TAX : PLA BRA .testAgainstMask .loadNormalFlags TXA : ASL : TAX : LDA.l UWEnemyItemFlags, X .testAgainstMask STA.b $02 : LDA.l SpriteDropData, X : AND.b $02 : EOR.b $02 BEQ .cleanup LDA.w #!BlueSquare : STA.w !EnemyDropIndicator .cleanup SEP #$10 : PLA : STA.b $02 .done SEP #$20 RTS ; Runs during sprite load of the room LoadSpriteData: INY : INY LDA.b [$00], Y CMP #$F3 : BCC .normal PHA DEC.b $03 ; standing items shouldn't consume a sprite slot LDX.b $03 ; these were changed to $03, for moved sprites CMP #$F9 : BNE .not_multiworld DEY : LDA.b [$00], Y : STA.l SprItemMWPlayer, X LDA.b #$02 : STA.l SprDropsItem, X : BRA .common .not_multiworld LDA.b #$00 : STA.l SprItemMWPlayer, X LDA.b #$01 : STA.l SprDropsItem, X DEY .common DEY : LDA.b [$00], Y : STA.l SprItemReceipt, X INY : INY PLA PLA : PLA ; remove the JSL return lower 16 bits PEA.w $09C344-1 ; change return address to exit from Underworld_LoadSingleSprite RTL .normal RTL ; Run when a sprite dies ... Sets Flag to #$02 and Index to sprite slot for RevealSpriteDrop: LDA.l SprDropsItem, X : BNE CheckIfDropValid JMP DoNormalDrop CheckIfDropValid: REP #$30 : PHX ; save it for later TXA : ASL : TAX : LDA.l BitFieldMasks, X : STA.b $00 ; stores the bitmask for the specific drop ; check sram, if gotten, run normal LDA.b $A0 : ASL : TAX : LDA.l SpriteDropData, X : PLX ; restore X in case we're done BIT.b $00 : BNE DoNormalDrop ; zero indicates the item has not been obtained PHX ; save it for later LDX.b $A0 : LDA.l UWSpecialFlagIndex, X : AND.w #$00FF CMP.w #$00FF : BEQ + ; $FF indicates the EnemyItemFlags are sufficient JSR FetchBitmaskForSpecialCase BRA .test + TXA : ASL : TAX : LDA.l UWEnemyItemFlags, X .test PLX : BIT.b $00 : BEQ DoNormalDrop ; zero indicates the enemy doesn't drop SEP #$30 ;This section sets up the drop LDA #$02 : STA.l SpawnedItemFlag STX.w SpawnedItemIndex LDA.l SprItemReceipt, X : STA SpawnedItemID LDA.l SprItemMWPlayer, X : STA SpawnedItemMWPlayer LDY.b #$01 ; trigger the small key routines LDA.w SpawnedItemID : STA.b $00 : CMP #$32 : BNE + LDA.l StandingItemsOn : BNE + INY ; big key routine + PHX LDA.l SpawnedItemMWPlayer : BNE .done ; abort check for absorbables it belong to someone else LDX.b #$00 ; see if the item should be replaced by an absorbable - CPX.b #$1A : BCS .done LDA.l MinorForcedDrops, X CMP.b $00 : BNE + INX : LDA.l MinorForcedDrops, X : STA.b $00 PLX : PLA : PLA : PEA.w $06F9D7-1 ; change call stack for PrepareEnemyDrop JSR IncrementCountForMinor LDA.b $00 : RTL + INX #2 : BRA - .done PLX RTL ; unstun if stunned DoNormalDrop: SEP #$30 LDY.w $0CBA, X : BEQ .no_forced_drop RTL .no_forced_drop PLA : PLA ; remove the JSL reswamturn lower 16 bits PEA.w $06F996-1 ; change return address to .no_forced_drop of (Sprite_DoTheDeath) RTL RevealSpriteDrop2: LDY.w SprDropsItem, X : BEQ .normal BRA .no_forced_drop .normal LDY.w $0CBA, X : BEQ .no_forced_drop RTL .no_forced_drop PLA : PLA ; remove the JSL reswamturn lower 16 bits PEA.w $06E3CE-1 ; change return address to .no_forced_drop of (Sprite_DoTheDeath) RTL ; input - A the index from UWSpecialFlagIndex ; uses X for loop, $02 for comparing first byte to dungeon ; output - A the correct bitmask FetchBitmaskForSpecialCase: ASL : TAX LDA.w $040C : BNE + ; could check if we are in a cave here and branch to different function? INC #2 ; move sewers to HC + STA.b $02 - LDA.l UWSpecialFlag, X : AND.w #$00FF CMP.w #$00FF : BNE + ; if the value is FF we are done, use 0 as bitmask LDA.w #$0000 : RTS + CMP.b $02 : BNE + ; if the value matches the dungeon, use next 2 bytes as bitmasl INX : LDA.l UWSpecialFlag, X : RTS + INX #3 : BRA - ; else move to the next row MinorForcedDrops: ; Item ID -> Sprite ID db $27, $DC ; BOMB REFILL 1 db $28, $DD ; BOMB REFILL 4 db $31, $DE ; BOMB REFILL 8 db $34, $D9 ; GREEN RUPEE ($34) db $35, $DA ; BLUE RUPEE ($35) db $36, $DB ; RED RUPEE ($36) db $42, $D8 ; HEART ($42) db $44, $E2 ; ARROW REFILL 10 ($44) db $45, $DF ; SMALL MAGIC DECANTER ($45) db $D2, $E3 ; FAERIE ($D2) db $D3, $0B ; CUCCO ($D3) db $D4, $E0 ; LARGE MAGIC DECANTER ($D4) db $D5, $E1 ; ARROW REFILL 5 (x$D5) IncrementCountForMinor: PHX : REP #$30 LDA.w SpawnedItemIndex : ASL : TAX : LDA.l BitFieldMasks, X : STA $0A LDA.b $A0 : ASL : TAX LDA.l SpriteDropData, X : BIT $0A : BNE .obtained ORA $0A : STA SpriteDropData, X SEP #$10 JSR SetupEnemyDropIndicator LDX.w $040C : CPX.b #$FF : BEQ + CPX.b #$00 : BNE ++ INX #2 ; treat sewers as HC ++ LDA.l DungeonLocationsChecked, X : INC : STA.l DungeonLocationsChecked, X ; Could increment GT Tower Pre Big Key but we aren't showing that stat right now + REP #$10 LDA TotalItemCounter : INC : STA TotalItemCounter ; Increment Item Total INC.w UpdateHUD .obtained SEP #$30 : PLX RTS BitFieldMasks: dw $8000, $4000, $2000, $1000, $0800, $0400, $0200, $0100 dw $0080, $0040, $0020, $0010, $0008, $0004, $0002, $0001 ; Runs during Sprite_E4_SmallKey and duning Sprite_E5_BigKey spawns ShouldSpawnItem: LDA $048E : CMP.b #$87 : BNE + ; check for hera basement cage CPX #$0A : BNE + ; the hera basement key is always sprite 0x0A LDA $A8 : AND.b #$03 : CMP.b #$02 : BNE + ; we're not in that quadrant LDA.w $0403 : AND.w KeyRoomFlagMasks,Y : RTL + ; checking our sram table PHX : PHY REP #$30 LDA.b $A0 : ASL : TAY LDA.w SprItemIndex, X : AND #$00FF : ASL PHX TAX : LDA.l BitFieldMasks, X : STA $00 PLX ; restore X again LDA.w SprItemFlags, X : AND #$00FF : CMP #$0001 : BEQ + TYX : LDA.l SpriteDropData, X : BIT $00 : BEQ .notObtained BRA .obtained + TYX : LDA.l RoomPotData, X : BIT $00 : BEQ .notObtained .obtained SEP #$30 : PLY : PLX : LDA #$01 : RTL ; already obtained .notObtained SEP #$30 : PLY : PLX LDA #$00 RTL MarkSRAMForItem: LDA $048E : CMP.b #$87 : BNE + ; check for hera basement cage CPX #$0A : BNE + ; the hera basement key is always sprite 0x0A LDA $A8 : AND.b #$03 : CMP.b #$02 : BNE + LDA.w $0403 : ORA.w KeyRoomFlagMasks, Y : RTL + PHX : PHY : REP #$30 LDA.b $A0 : ASL : TAY LDA.l SpawnedItemIndex : ASL TAX : LDA.l BitFieldMasks, X : STA $00 TYX LDA.w SpawnedItemFlag : CMP #$0001 : BEQ + LDA SpriteDropData, X : ORA $00 : STA SpriteDropData, X SEP #$10 : JSR SetupEnemyDropIndicator BRA .end + LDA RoomPotData, X : ORA $00 : STA RoomPotData, X .end SEP #$30 : PLY : PLX LDA.w $0403 RTL SpriteKeyPrep: LDA.w $0B9B : STA.w $0CBA, X ; what we wrote over PHA LDA $A0 : CMP #$87 : BNE .continue CPX #$0A : BNE .continue ; the hera basement key is always sprite 0x0A LDA $A9 : ORA $AA : AND #$03 : CMP #$02 : BNE .continue LDA #$00 : STA.w SpawnedItemFlag : STA SprItemFlags, X LDA #$24 : STA $0E80, X BRA + .continue LDA.w SpawnedItemIndex : STA SprItemIndex, X LDA.w SpawnedItemMWPlayer : STA SprItemMWPlayer, X : STA.w !MULTIWORLD_SPRITEITEM_PLAYER_ID LDA.w SpawnedItemFlag : STA SprItemFlags, X : BEQ + LDA.l SpawnedItemID : STA $0E80, X PHA : PHY : PHX JSL.l GetSpritePalette : PLX : STA $0F50, X ; setup the palette PLY : PLA CMP #$24 : BNE ++ ; LDA $A0 : CMP.b #$80 : BNE + LDA SpawnedItemFlag : BNE + LDA #$24 ; it's the big key drop? ++ JSL RequestStandingItemVRAMSlot + PLA RTL SpriteKeyDrawGFX: JSL Sprite_DrawRippleIfInWater PHA LDA $0E80, X CMP.b #$24 : BNE + LDA $A0 : CMP #$80 : BNE ++ LDA SpawnedItemFlag : BNE ++ LDA #$24 : BRA + ++ PLA PHK : PEA.w .jslrtsreturn-1 PEA.w $068014 ; an rtl address - 1 in Bank06 JML Sprite_DrawAbsorbable .jslrtsreturn RTL + JSL DrawPotItem CMP #$03 : BNE + PHA : LDA $0E60, X : ORA.b #$20 : STA $0E60, X : PLA + JSL.l Sprite_DrawShadowLong PLA : RTL KeyGet: LDA CurrentSmallKeys ; what we wrote over PHA LDA.l StandingItemsOn : BNE + PLA : RTL + LDY $0E80, X LDA SprItemIndex, X : STA SpawnedItemIndex LDA SprItemFlags, X : STA SpawnedItemFlag LDA $A0 : CMP #$87 : BNE + ;check for hera cage LDA SpawnedItemFlag : BNE + ; if it came from a pot, it's fine JSR ShouldKeyBeCountedForDungeon : BCC ++ JSL CountChestKeyLong ++ PLA : RTL + STY $00 LDA SprItemMWPlayer, X : STA !MULTIWORLD_ITEM_PLAYER_ID : BNE .receive PHX LDA $040C : CMP #$FF : BNE + LDA $00 : CMP.b #$AF : BNE .skip LDA CurrentGenericKeys : INC : STA CurrentGenericKeys LDA $00 : BRA .countIt + LSR : TAX LDA $00 : CMP.l KeyTable, X : BNE + .countIt LDA.l StandingItemCounterMask : AND SpawnedItemFlag : BEQ ++ JSL.l AddInventory : JSL CountChestKeyLong ++ PLX : PLA : RTL + CMP.b #$AF : beq .countIt ; universal key CMP.b #$24 : beq .countIt ; small key for this dungeon .skip PLX .receive JSL $0791b3 ; Player_HaltDashAttackLong JSL.l Link_ReceiveItem PLA : DEC : RTL KeyTable: db $A0, $A0, $A2, $A3, $A4, $A5, $A6, $A7, $A8, $A9, $AA, $AB, $AC, $AD ; Input Y - the item type ShouldKeyBeCountedForDungeon: PHX LDA $040C : CMP #$FF : BEQ .done LSR : TAX TYA : cmp KeyTable, X : BNE + - PLX : SEC : RTS + CMP.B #$24 : BEQ - .done PLX : CLC : RTS BigKeyGet: LDY $0E80, X CPY #$32 : BNE + STZ $02E9 : LDY.b #$32 ; what we wrote over PHX : JSL Link_ReceiveItem : PLX ; what we wrote over CLC : RTL + SEC : RTL LoadProperties_PreserveCertainProps: LDA $0E20, X : CMP #$E4 : BEQ + CMP #$E5 : BEQ + JML Sprite_LoadProperties + LDA $0F50, X : PHA LDA $0E80, X : PHA JSL Sprite_LoadProperties PLA : STA $0E80, X PLA : STA $0F50, X RTL SubstitionFlow: CPY.b #$04 : BNE + RTL ; let enemizer/vanilla take care of it + PLA : PLA ; remove JSL stuff CPY.b #$16 : BCS + PEA.w Sprite_SpawnSecret_NotRandomBush-1 : RTL ; jump to not_random_bush spot ; jump directly to new code + PEA.w Sprite_SpawnSecret_SpriteSpawnDynamically-1 RTL SubstitionTable: db $DB ; RED RUPEE - 0x16 db $E2 ; ARROW REFILL 10 - 0x17 db $DD ; BOMB REFILL 4 - 0x18 db $DE ; BOMB REFILL 8 - 0x19 SubstituteSpriteId: CPY.b #$16 : BCS + RTS + LDA.b #$01 CPY.b #$18 : BCC + LDA.b #$05 + STA.b $0D JSR IncrementCountsForSubstitute PHB : PHK : PLB LDA.w SubstitionTable-$16, Y ; Do substitute PLB RTS CheckSprite_Spawn: JSR SubstituteSpriteId JSL Sprite_SpawnDynamically BMI .check RTL .check LDA $0D : CMP #$08 : BNE + LDA $0372 : BNE .error LDX #$0F ; loop looking for a Sprite with state 0A (carried by the player) - LDA $0DD0, X : CMP #$0A : BEQ .foundIt DEX : BMI .error : BRA - .foundIt LDA #$00 : STZ $0DD0, X LDA #$E4 : JSL Sprite_SpawnDynamically BMI .error LDA #$40 : TSB $0308 : RTL .error LDA.b #$3C ; SFX2_3C - error beep STA.w $012E + LDA #$FF RTL PreventPotSpawn: LDA #$40 : BIT $0308 : BEQ + STZ $0308 : RTL + LDA.b #$80 : STA.w $0308 ; what we wrote over RTL PreventPotSpawn2: LDA $0308 : BEQ + LDA.b #$01 : TSB.b $50 ; what we wrote over + RTL CheckIfPotIsSpecial: TXA ; give index to A so we can do a CMP.l CMP.l $018550 ; see if our current index is that of object 230 BEQ .specialpot ; Normal pot, so run the vanilla code LDA.l $7EF3CA ; check for dark world .specialpot ; zero flag already set, so gtg RTL SetTheSceneFix: STZ.b $6C JSL InitializeMirrorHDMA JSL LoadCommonSprites_long RTL incsrc dynamic_si_vram.asm ;=================================================================================================== ; Pot items ;=================================================================================================== ;Vanilla: ; Data starts at $01DDE7 formatted: ; dw aaaa : db i ; aaaa is a 14 bit number: ..tt tttt tttt tttt indicating the tilemap ID ; i is the secrets ID ;Drop shuffle changes: ; normal secrets stay vanilla ; major items (anything not a secret) use the bits 14 and 15 to produce different behavior ; aaaa is now a 16 bit number: ; imtt tttt tttt tttt ; t - is still tilemap id (aaaa & #$3FFF) ; i - flag indicates a major item ; m - indicates a multiworld item ; for major items (non multiworld), i indicates the item receipt ID ; for multi world items, i indicates the multiworld id ; multiworld id indexes a new table of 256 entries of 2 bytes each ; MultiWorldTable: ; db , ;=================================================================================================== ; Sprite items ;=================================================================================================== ;Vanilla: ;If this value appears in the sprite table, then the sprite that preceded it is given a key drop ; db $FE, $00, $E4 ;Drop shuffle changes: ; db , $00, $F8 ; this denotes the previous sprite is given a major item (non MW) ; db , , $F9 ; this denotes the previous sprite is given a MW item