From 78b5695e30e4a3821844cc6bfcda003e30f740c3 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 17 Aug 2023 13:39:18 -0600 Subject: [PATCH] Prevent cross dungeon drops Enemy drop indicator prototype --- doorrando/hudadditions.asm | 213 ++++++++++++++++++++++++++----------- keydrop/standing_items.asm | 124 +++++++++++++++++++-- ram.asm | 24 ++++- util/utils.asm | 2 +- 4 files changed, 290 insertions(+), 73 deletions(-) diff --git a/doorrando/hudadditions.asm b/doorrando/hudadditions.asm index 83304b1..aaf6a1a 100644 --- a/doorrando/hudadditions.asm +++ b/doorrando/hudadditions.asm @@ -1,73 +1,156 @@ +!BlankTile = $207F +!SlashTile = $2830 +!HyphenTile = $2405 +!PTile = $296C +!CTile = $295F +!RedSquare = $345E +!BlueSquare = $2C5E + +!DungeonMask = $8098C0 +!EnemyDropIndicator = $7E072A +!IndicatorAddress = $7EC790 ; used for both boss nearness and enemy drops +!CurrentDungeonIndicator = $7EC702 + +!KeysObtained = $7EC7A2 +!KeysSlash = $7EC7A4 +!KeysTotal = $7EC7A6 + DrHudOverride: -{ - jsl.l NewDrawHud - jsr HudAdditions - rtl -} + PHB + SEP #$30 + LDA.b #$7E + PHA + PLB -HudAdditions: -{ - SEP #$10 - LDA.l DRFlags : AND #$0008 : BNE + : JMP .end_item_count : + - LDA.l TotalItemCounter : PHA : CMP #1000 : !BLT + - JSL HexToDec4Digit_fast - LDX.b $04 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS ; draw 1000's digit - BRA .skip - + JSL HexToDec_fast - .skip - LDA #$207F : STA !GOAL_DRAW_ADDRESS+2 : STA !GOAL_DRAW_ADDRESS+4 - PLA : PHA : CMP.w #100 : !BLT + - LDX.b $05 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+2 ; draw 100's digit - + PLA : CMP.w #10 : !BLT + - LDX.b $06 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+4 ; draw 10's digit - + LDX.b $07 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+6 ; draw 1's digit - LDA.w #$2830 : STA !GOAL_DRAW_ADDRESS+8 ; draw slash - LDA.l DRFlags : AND #$0100 : BNE + - LDA.l MultiClientFlagsWRAM+1 : CMP #1000 : !BLT .three_digit_goal - JSL HexToDec4Digit_fast - LDX.b $04 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+10 ; draw 1000's digit - LDX.b $05 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+12 ; draw 100's digit - LDX.b $06 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+14 ; draw 10's digit - LDX.b $07 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+16 ; draw 1's digit - BRA .end_item_count - .three_digit_goal - JSL HexToDec_fast - LDX.b $05 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+10 ; draw 100's digit - LDX.b $06 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+12 ; draw 10's digit - LDX.b $07 : TXA : ORA.w #$2490 : STA !GOAL_DRAW_ADDRESS+14 ; draw 1's digit - BRA .end_item_count - + LDA.w #$2405 : STA !GOAL_DRAW_ADDRESS+10 : STA !GOAL_DRAW_ADDRESS+12 - STA !GOAL_DRAW_ADDRESS+14 : STA !GOAL_DRAW_ADDRESS+16 - .end_item_count +DRHUD_DrawItemCounter: + LDA.l DRFlags : AND #$08 : BNE .draw + JMP DRHUD_DrawIndicators - LDX $1B : BNE + : RTS : + ; Skip if outdoors - ldx $040c : cpx #$ff : bne + : rts : + ; Skip if not in dungeon - lda.l DRMode : bne + : rts : + ; Skip if not door rando - phb : phk : plb - lda CompassField : and.l $0098c0, x : beq + - lda.w CompassBossIndicator, x : and #$00ff : cmp $a0 : bne + - lda $1a : and #$0010 : beq + - lda #$345e : sta $7ec790 : bra .next - + lda #$207f : sta $7ec790 - .next lda.w DRMode : and #$0002 : bne + : plb : rts : + - lda CurrentHealth : and #$00ff : beq + - lda.w DungeonReminderTable, x : bra .reminder - + lda #$207f - .reminder sta $7ec702 - + lda.w DRFlags : and #$0004 : beq .restore - lda MapField : and.l $0098c0, x : beq .restore - txa : lsr : tax +.draw + REP #$30 + LDY.w #!SlashTile : STY.w !GOAL_DRAW_ADDRESS+8 + LDA.l TotalItemCounter : PHA + JSR DRHUDHex4Digit - lda.l GenericKeys : and #$00ff : bne + - lda DungeonCollectedKeys, x : jsr ConvertToDisplay : sta $7ec7a2 - lda #$2830 : sta $7ec7a4 - + - lda.w ChestKeys, x : jsr ConvertToDisplay : sta $7ec7a6 - ; todo 4b0 no longer in use + LDY.w #!BlankTile ; copy these from newhud + LDA.b $04 : TAX : STX.w !GOAL_DRAW_ADDRESS+0 + LDA.b $05 : TAX : STX.w !GOAL_DRAW_ADDRESS+2 + LDA.b $06 : TAX : STX.w !GOAL_DRAW_ADDRESS+4 + LDA.b $07 : TAX : STX.w !GOAL_DRAW_ADDRESS+6 + PLX + CPX.w #1000 : BCS .leave_remaining_digits + STY.w !GOAL_DRAW_ADDRESS + CPX.w #100 : BCS .leave_remaining_digits + STY.w !GOAL_DRAW_ADDRESS+2 + CPX.w #10 : BCS .leave_remaining_digits + STY.w !GOAL_DRAW_ADDRESS+4 +.leave_remaining_digits + LDA.l DRFlags+1 : LSR : BCC .real_goal + LDY.w #!HyphenTile : STA.w !GOAL_DRAW_ADDRESS+10 : STA.w !GOAL_DRAW_ADDRESS+12 + STA.w !GOAL_DRAW_ADDRESS+14 : STA.w !GOAL_DRAW_ADDRESS+16 + BRA DRHUD_DrawIndicators + +.real_goal + REP #$30 + LDA.l MultiClientFlagsWRAM+1 : CMP.w #1000 : BCS .four_digits + JSR DRHUDHex3Digit + LDA.b $05 : TAX : STX.w !GOAL_DRAW_ADDRESS+10 + LDA.b $06 : TAX : STX.w !GOAL_DRAW_ADDRESS+12 + LDA.b $07 : TAX : STX.w !GOAL_DRAW_ADDRESS+14 + BRA DRHUD_DrawIndicators + +.four_digits + JSR DRHUDHex4Digit ; carry will be preserved + LDA.b $04 : TAX : STX.w !GOAL_DRAW_ADDRESS+10 + LDA.b $05 : TAX : STX.w !GOAL_DRAW_ADDRESS+12 + LDA.b $06 : TAX : STX.w !GOAL_DRAW_ADDRESS+14 + LDA.b $07 : TAX : STX.w !GOAL_DRAW_ADDRESS+16 + +DRHUD_DrawIndicators: + SEP #$30 + LDA.b $1B : BNE .continue + JMP DRHUD_Finished +.continue + LDA.b $1A : AND.b #$10 : BEQ DRHUD_EnemyDropIndicator + +DRHUD_BossIndicator: + LDA.l DRMode : BNE .continue +.early_exit + JMP DRHUD_Finished +.continue + LDA.w $040C : CMP.b #$1B : BCS .early_exit + + SEP #$10 ; clears the high byte of X and prevents it from getting B register + TAX + + REP #$30 + LDY.w #!BlankTile + LDA.w CompassField : AND.l DungeonMask, x + SEP #$20 + BEQ .draw_indicator + LDA.l CompassBossIndicator, x : CMP.b $A0 : BNE .draw_indicator + LDY.w #!RedSquare +.draw_indicator + STY.w !IndicatorAddress + BRA DRHUD_DrawCurrentDungeonIndicator + +DRHUD_EnemyDropIndicator: + REP #$30 + LDA.w !EnemyDropIndicator : STA.w !IndicatorAddress + SEP #$20 + LDA.w $040C : CMP.b #$1B : BCS DRHUD_Finished + SEP #$10 : TAX : REP #$10 + +DRHUD_DrawCurrentDungeonIndicator: ; mX + LDA.l DRMode : AND.b #$02 : BEQ DRHUD_Finished + LDY.w #!BlankTile + LDA.w CurrentHealth : BEQ .draw_indicator + + REP #$20 : LDA.l DungeonReminderTable,X : SEP #$20 + TAY +.draw_indicator + STY.w !CurrentDungeonIndicator + +DRHUD_DrawKeyCounter: + LDA.l DRFlags : AND.b #$04 : BEQ DRHUD_Finished + REP #$20 + LDA.w MapField : AND.l DungeonMask, X : BEQ DRHUD_Finished + TXA : LSR : TAX + LDA.l GenericKeys : AND.w #$00FF : BNE .total_only + LDA.l DungeonCollectedKeys, X : JSR ConvertToDisplay : STA.w !KeysObtained + LDA #!SlashTile : STA.w !KeysSlash +.total_only + LDA.l ChestKeys, x : JSR ConvertToDisplay : STA.w !KeysTotal + +;=================================================================================================== + +DRHUD_Finished: + PLB : RTL + +;=================================================================================================== + +DRHUDHex3Digit: + JSL HexToDec_fast + JMP DRHUDHex4Digit_shared + +DRHUDHex4Digit: + JSL HexToDec4Digit_fast +.shared + REP #$30 + LDA.l $04 + ORA.w #$9090 + STA.b $04 + + LDA.l $06 + ORA.w #$9090 + STA.b $06 + LDA.w #$2400 ; 2490 + + SEP #$20 + RTS + +;=================================================================================================== - .restore - plb : rts -} ;column distance for BK/Smalls HudOffsets: diff --git a/keydrop/standing_items.asm b/keydrop/standing_items.asm index 8c04acd..e410dde 100644 --- a/keydrop/standing_items.asm +++ b/keydrop/standing_items.asm @@ -96,6 +96,7 @@ SpawnedItemIsMultiWorld = $7E0724 ; 0x02 SpawnedItemFlag = $7E0726 ; 0x02 - one for pot, 2 for sprite drop ; (flag used as a bitmask in conjunction with StandingItemCounterMask) SpawnedItemMWPlayer = $7E0728 ; 0x02 +;!EnemyDropIndicator = $7E072A ; 0x02 either the blank tile or the blue square ; clear all of them in a loop during room load SprDropsItem = $7E0730 ; 0x16 SprItemReceipt = $7E0740 ; 0x16 @@ -148,12 +149,43 @@ UWEnemyItemFlags: ; Reserved $250 296 * 2 -; Thoughs on multitile dungeon design +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: @@ -163,8 +195,7 @@ UWEnemyItemFlags: ; $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 $A8AF00 - +org $A8B128 RevealPotItem: STA.b $04 ; save tilemap coordinates STZ.w SpawnedItemFlag @@ -320,6 +351,7 @@ ClearSpriteData: STA SprDropsItem, X : STA SprItemReceipt, X : STA SprItemIndex, X STA SprItemMWPlayer, X : STA SprItemFlags, X INX : CPX #$10 : BCC .loop + JSR SetupEnemyDropIndicator PLX RTL @@ -327,6 +359,49 @@ 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 SpritePotData, 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 @@ -354,7 +429,24 @@ LoadSpriteData: ; Run when a sprite dies ... Sets Flag to #$02 and Index to sprite slot for RevealSpriteDrop: - LDA.l SprDropsItem, X : BEQ .normal + 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 SpritePotData, 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 @@ -377,7 +469,9 @@ RevealSpriteDrop: + INX #2 : BRA - .done PLX RTL ; unstun if stunned - .normal + +DoNormalDrop: + SEP #$30 LDY.w $0CBA, X : BEQ .no_forced_drop RTL .no_forced_drop @@ -396,6 +490,21 @@ RevealSpriteDrop2: 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 @@ -420,6 +529,7 @@ IncrementCountForMinor: LDA.l SpritePotData, X : BIT $0A : BNE .obtained ORA $0A : STA SpritePotData, X SEP #$30 + JSR SetupEnemyDropIndicator LDA $040C : CMP #$FF : BEQ + CMP #$00 : BNE ++ INC #2 ; treat sewers as HC @@ -472,7 +582,9 @@ MarkSRAMForItem: TAX : LDA.l BitFieldMasks, X : STA $00 TYX LDA.w SpawnedItemFlag : CMP #$0001 : BEQ + - LDA SpritePotData, X : ORA $00 : STA SpritePotData, X : BRA .end + LDA SpritePotData, X : ORA $00 : STA SpritePotData, X + SEP #$10 : JSR SetupEnemyDropIndicator + BRA .end + LDA RoomPotData, X : ORA $00 : STA RoomPotData, X .end SEP #$30 : PLY : PLX diff --git a/ram.asm b/ram.asm index 3510b8f..11ff2f2 100644 --- a/ram.asm +++ b/ram.asm @@ -1,12 +1,26 @@ ;================================================================================ ; RAM Labels & Assertions ;-------------------------------------------------------------------------------- +pushpc +org 0 +;-------------------------------------------------------------------------------- ; Labels for values in WRAM and assertions that ensure they're correct and ; at the expected addresses. All values larger than one byte are little endian. ;-------------------------------------------------------------------------------- ; Placeholder and for compass item max count allocations, still WIP ;-------------------------------------------------------------------------------- -CompassTotalsWRAM = $7F5410 + +base $7F5000 +RedrawFlag: skip 1 ; +skip 2 ; Unused +HexToDecDigit1: skip 1 ; Space for storing the result of hex to decimal conversion. +HexToDecDigit2: skip 1 ; Digits are stored from high to low. +HexToDecDigit3: skip 1 ; +HexToDecDigit4: skip 1 ; +HexToDecDigit5: skip 1 ; + +base $7F5410 +CompassTotalsWRAM: skip $10 ;================================================================================ ; RAM Assertions @@ -15,4 +29,12 @@ macro assertRAM(label, address) assert