Files
alttpr-baserom/goalitem.asm
2025-11-08 10:29:41 -06:00

429 lines
10 KiB
NASM

GoalItemGanonCheck:
LDA.w SpriteTypeTable, X : CMP.b #$D6 : BNE .success ; skip if not ganon
LDA.b #$01 : JSL CheckConditionPass
BCS .success
.fail
LDA.w SpriteActivity, X : CMP.b #17 : !BLT .success ; decmial 17 because Acmlm's chart is decimal
LDA.b #$00
RTL
.success
LDA.b OAMOffsetY : CMP.b #$80 ; thing we wrote over
RTL
;--------------------------------------------------------------------------------
; Input A = Type of condition check
; Carry clear = failed check
; Carry set = successful check
CheckConditionPass:
PHX : PHY
PHB
LDY.b #GoalConditionTable>>16 : PHY : PLB : STY.b Scrap02
REP #$20
ASL : TAY
LDA.w GoalConditionTable, Y : STA.b Scrap00
PHK : PLB
SEP #$20
LDY.b #$00
- LDA.b [Scrap00], Y : CMP.b #$FF : BEQ .exit
INY : ROL : TAX
JSR (.conditions, X) : BCC .exit : BRA -
.exit
PLB : PLY : PLX
RTL
; Y = index after condition code
; Carry = Set if using default target value
.conditions
dw .always_fail
dw .pendants
dw .crystals
dw .pendant_bosses
dw .crystal_bosses
dw .bosses
dw .agahnim_defeated
dw .agahnim2_defeated
dw .goal_item
dw .collection_rate
dw .custom_goal
dw .bingo
dw .success
dw .success
dw .success
dw .success
.agahnim2_defeated
LDA.l RoomDataWRAM[$0D].high : AND.b #$08 : BEQ .fail
.bingo ; not implemented yet
.success
SEC : RTS
.always_fail
.fail
CLC : RTS
.pendants
PHP
LDA.l PendantCounter : PLP : BCC +
CMP.b #$03 : RTS
.crystals
PHP
LDA.l CrystalCounter : PLP : BCC +
CMP.b #$07 : RTS
.pendant_bosses
PHP
LDA.b #$02
JSR CheckForBossesDefeated : PLP : BCC +
CMP.b #$03 : RTS
.crystal_bosses
PHP
LDA.b #$01
JSR CheckForBossesDefeated : PLP : BCC +
CMP.b #$07 : RTS
.bosses
PHP
LDA.b #$00
JSR CheckForBossesDefeated : PLP : BCC +
CMP.b #$10 : RTS
+ CMP.b [Scrap00], Y : INY : RTS
.agahnim_defeated
LDA.l ProgressIndicator : CMP.b #$03 : RTS
.goal_item
REP #$20
LDA.l GoalCounter : BCC +
CMP.l GoalItemRequirement : BRA ++
.collection_rate
REP #$20
LDA.l TotalItemCounter : BCC +
CMP.l TotalItemCount : BRA ++
+ CMP.b [Scrap00], Y : INY : INY : ++
SEP #$20
RTS
.custom_goal
LDA.b [Scrap00], Y : INY ; options
PHA : AND.b #$07 : ASL : TAX : PLA
;JMP CheckConditionPassCustom
; flows into next function, do not insert code after without uncommenting above
; --------------------------------------------------------------------------------
; Input A = Options value, see GoalConditionTable for format
; Input X = Condition check type index
; Input Y = Index after Options byte
CheckConditionPassCustom:
PHX : PHA : BIT.b #$08 : PHP
REP #$30
LDA.b [Scrap00], Y : INY : INY ; address
PLP : REP #$30 : BEQ .byte
.word
TAX
SEP #$20
PLA
AND.b #$10
REP #$20
BNE +
LDA.l $7E0000, X : BRA ++
+
LDA.l $7F0000, X : ++
SEP #$10
PLX
REP #$10
JSR (.comparisons, X)
INY
SEP #$30
RTS
.byte
TAX
SEP #$20
PLA
AND.b #$10 : BNE +
LDA.l $7E0000, X : BRA ++
+
LDA.l $7F0000, X : ++
SEP #$10
PLX
JMP (.comparisons, X)
.comparisons
dw .minimum
dw .exact
dw .bitfield_nonzero
dw .bitfield_match
dw .count_bits
dw .fail
dw .fail
dw .fail
.pass
INY : SEC : RTS
.count_bits
JSL CountBits
.minimum
CMP.b [Scrap00], Y : INY
RTS
.bitfield_match
AND.b [Scrap00], Y
.exact
CMP.b [Scrap00], Y : BEQ .pass
INY : CLC : RTS
.bitfield_nonzero
AND.b [Scrap00], Y : BNE .pass
.fail
INY : CLC : RTS
;--------------------------------------------------------------------------------
GTCutscene_TransferGfx:
PHA
REP #$20
STZ.w DuckPose
LDA.l GanonsTowerOpenGfx : BEQ .original_crystal
PHX
LDX.w ItemStackPtr : STA.l ItemGFXStack,X
LDA.w #$81C0>>1 : STA.l ItemTargetStack,X
INX #2 : STX.w ItemStackPtr
PLX
SEP #$20
PLA
RTL
.original_crystal
SEP #$20
PLA
JML TransferItemReceiptToBuffer_using_GraphicsID
;--------------------------------------------------------------------------------
AncillaDraw_GTCutsceneCrystal_OAMPrep:
LDA.l GanonsTowerOpenGfx : ORA.l GanonsTowerOpenGfx+1 : BEQ .vanilla
LDA.b #$0E : STA.b (OAMPtr),Y
INY
LDA.l GanonsTowerOpenPalette : AND.b #$67 : ASL : ORA.b #$30
STA.b (OAMPtr),Y
RTL
.vanilla
LDA.b #$24 : STA.b (OAMPtr),Y
INY
LDA.b #$3C : STA.b (OAMPtr),Y
RTL
;--------------------------------------------------------------------------------
GTCutscene_CrystalMasks:
db %00000000 ; 0 crystals
db %10000000 ; BIT INDEX DIAGRAM
db %00010010 ; 0
db %00010101 ; 5 1
db %10010101 ; 7
db %10110110 ; 4 2
db %00111111 ; 3
db %10111111 ; 7 crystals
;--------------------------------------------------------------------------------
GTCutscene_ConditionalAnimateCrystals:
PHX : PHX
JSR GTCutscene_NumberOfCrystals : TAX : LDA.l GTCutscene_CrystalMasks,X
PLX
- LSR : DEX : BPL -
PLX : BCC .skip_crystal
.draw_crystal
LDA.b GameSubMode : BEQ + : JML GTCutscene_AnimateCrystals_NoRotate ; what we wrote over
+ JML GTCutscene_AnimateCrystals_NextCrystal+4
.skip_crystal
JML GTCutscene_DrawSingleCrystal-3
;--------------------------------------------------------------------------------
GTCutscene_ConditionalDrawSingleCrystal:
LDA.w RandoOverworldTargetEdge : BEQ .draw_crystal : STZ.w RandoOverworldTargetEdge
JSR GTCutscene_NumberOfCrystals : TAX
LDA.l GTCutscene_CrystalMasks,X : AND.b #$80 : BEQ .skip_crystal
.draw_crystal
LDX.w CurrentSpriteSlot : PHY ; what we wrote over
JML GTCutscene_DrawSingleCrystal+4
.skip_crystal
JML GTCutscene_DrawSingleCrystal_SkipCrystal
;--------------------------------------------------------------------------------
GTCutscene_AnimateCrystals_Prep:
BEQ + : JSL GTCutscene_SparkleALot : + ; thing we wrote over
JSR GTCutscene_NumberOfCrystals : BNE +
JML GTCutscene_DrawSingleCrystal_SkipSparkle
+ CMP.b #$01 : BNE +
JML GTCutscene_DrawSingleCrystal
+ INC.w RandoOverworldTargetEdge ; some free ram OWR also uses
JML GTCutscene_AnimateCrystals_NextCrystal-2
;--------------------------------------------------------------------------------
GTCutscene_ActivateSparkle_SelectCrystal:
JSR GTCutscene_NumberOfCrystals : BNE +
TAX : RTL
+ STA.b Scrap00
TXA
- CMP.l Scrap00 : BCC +
SBC.l Scrap00 : BRA - ; carry guaranteed set
+ PHY : TAY
LDA.b Scrap00 : TAX : LDA.l GTCutscene_CrystalMasks,X
LDX.b #$FF
- LSR : INX : BCC +
DEY
+ BPL -
PLY
RTL
;--------------------------------------------------------------------------------
; prioritizes: number of gfx used > sum of targets > number of goals
; Scrap00 stores number of goals
; Y sums all goal target values
GTCutscene_NumberOfCrystals:
PHX : PHY : PHP
REP #$20
LDA.l GanonsTowerOpenGfx+2 : BEQ .not_multiple_gfx
LDX.b #$04
- LDA.l GanonsTowerOpenGfx, X : BEQ +
INX : INX : CPX.b #$0E : BCC -
+
TXA : LSR
JMP .done
.not_multiple_gfx
LDX.b #$00 : LDA.l GoalConditionTable, X
TXY : STY.b Scrap00
REP #$10
SEP #$20
TAX
.next
LDA.l $B00000, X : CMP.b #$FF : BNE + : JMP .use_y : +
INC.b Scrap00
ROL : PHP : CMP.b #$10 : BCS .not_8bit_compare
CMP.b #$0C : BEQ .agas_goal
CMP.b #$0E : BEQ .agas_goal
; uses 8-bit targets
PLP : BCC .use_8bit_target
CMP.b #$04 : BEQ .crystal_goal ; crystal goal
CMP.b #$08 : BEQ .crystal_goal ; crystal bosses goal
CMP.b #$02 : BEQ .pendant_goal ; pendant goal
CMP.b #$06 : BEQ .pendant_goal ; pendant bosses goal
BRA .bosses_goal
.crystal_goal
LDA.b #$07 : INX : BRA .add_to_y
.pendant_goal
LDA.b #$03 : INX : BRA .add_to_y
.bosses_goal
INY : INX : BRA .next ; just increment Y by 1 since default of 10 is already more than max 7
.agas_goal
PLP : INX : BRA .next
.use_8bit_target
INX : LDA.l $B00000, X : INX
.add_to_y
PHY : CLC : ADC.b 1,S : PLY : TAY : BRA .next
.not_8bit_compare
CMP.b #$14 : BEQ .custom_goal : BCS .unknown
; triforce hunt/collection rate - uses 16-bit targets
PLP : INX : BCC +
LDA.l $B00000, X : INX : INX : BRA .add_to_y
+ INY : BRA .next
.custom_goal
PLP
INX : LDA.l $B00000, X : BIT.b #$08 : PHP
INX : INX : INX : AND.b #$03 : BEQ .use_custom_target
; comparison method doesn't use a quantity, increment Y by 1
INY : INX : PLP : BEQ +
INX
+
BRA .next
.use_custom_target
PLP : BEQ ..8bit
; 16-bit target
REP #$20
LDA.l $B00000, X : CMP.w #$0008 : SEP #$20 : INX : BRA +
..8bit
LDA.l $B00000, X : CMP.b #$08 : + : BCC +
; target exceeds 7, just increment Y by 1
INY : INX : JMP .next
+
INX : BRA .add_to_y
.unknown ; unknown condition, exit with safe value
PLP : INY
.use_y
TYA : BEQ + : CMP.b #$08 : BCC .done
+ LDA.b Scrap00 : BEQ .use_one : CMP.b #$08 : BCC .done
.use_one
LDA.b #$01
.done
PLP : PLY : PLX
RTS
;--------------------------------------------------------------------------------
CheckTowerOpen:
LDA.b #$00 : JML CheckConditionPass
;---------------------------------------------------------------------------------------------------
CheckAgaForPed:
REP #$20
; seems light_speed option to force blue balls is unused for now
BRA .vanilla
.light_speed
SEP #$20
LDA.l OverworldEventDataWRAM+$80 ; check ped flag
AND.b #$40
BEQ .force_blue_ball
.vanilla ; run vanilla check for phase
SEP #$20
LDA.w SpriteAux, X
CMP.b #$02
RTL
.force_blue_ball
LDA.b #$01 : STA.w SpriteAuxTable, Y
LDA.b #$20 : STA.w SpriteTimer, Y
CLC ; skip the RNG check
RTL
;---------------------------------------------------------------------------------------------------
CheckForBossesDefeated:
PHB : PHX : PHY
STA.b Scrap04 ; 0 = check all, 1 = check crystals, 2 = check pendants
LDA.b #CrystalPendantFlags_3>>16
PHA : PLB
STZ.b Scrap03 ; count of number of bosses killed
STZ.b Scrap05
REP #$30
LDY.w #10
.next_check
LDA.w CrystalPendantFlags_3+2,Y : AND.w #$00FF : BEQ .skip
CMP.w #$0008 ; C set = pendant, C clear = crystal
LDA.b Scrap04 : BEQ .proceed
PHP : ROR : BCC +
PLP : BCS .skip : BRA .proceed
+ PLP : BCC .skip
.proceed
TYA : ASL : TAX
LDA.l DungeonMapBossRooms+4,X
ASL : TAX
LDA.l RoomDataWRAM.l,X
AND.w #$0800 : BEQ .skip
INC.b Scrap03
.skip
DEY : BPL .next_check
SEP #$30
PLY : PLX : PLB
LDA.b Scrap03
RTS
;---------------------------------------------------------------------------------------------------
CheckPedestalPull:
; Out: c - Successful ped pull if set, do nothing if unset.
LDA.b #$02 : JSL CheckConditionPass : BCS .return
PHX : PHP
LDA.b GameMode : CMP.b #$0E : BEQ +
REP #$30
LDX.w #$0004 : LDA.l GoalConditionTable, X : TAX
LDA.l $B00000, X : CMP.w #$FF81 : BEQ +
SEP #$30
LDA.b #$97 : LDY.b #$01
JSL Sprite_ShowMessageUnconditional
+
PLP : PLX
.return
RTL