Implemented Custom Goal Framework

This commit is contained in:
codemann8
2025-10-29 00:08:16 -05:00
parent a9ef09e2d0
commit 2ffcb1c3bd
6 changed files with 339 additions and 203 deletions

View File

@@ -265,7 +265,7 @@ RTL
RTL RTL
;-------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------
DialogGanon1: DialogGanon1:
JSL CheckGanonVulnerability LDA.b #$01 : JSL CheckConditionPass
REP #$20 REP #$20
LDA.w #$018C LDA.w #$018C
BCC + BCC +
@@ -284,7 +284,7 @@ RTL
; s = silver arrow bow ; s = silver arrow bow
; p = 2nd progressive bow ; p = 2nd progressive bow
DialogGanon2: DialogGanon2:
JSL CheckGanonVulnerability LDA.b #$01 : JSL CheckConditionPass
REP #$20 REP #$20
BCS + BCS +
@@ -372,8 +372,8 @@ RTL
;--------------------------------------------------------------------------------------------------- ;---------------------------------------------------------------------------------------------------
AgahnimAsksAboutPed: AgahnimAsksAboutPed:
LDA.l GanonVulnerableMode ; seems light_speed option to change some aga text is unused for now
CMP.b #$06 : BNE .vanilla BRA .vanilla
LDA.l OverworldEventDataWRAM+$80 ; check ped flag LDA.l OverworldEventDataWRAM+$80 ; check ped flag
AND.b #$40 AND.b #$40

View File

@@ -39,32 +39,30 @@ RTL
Elder_Code: Elder_Code:
{ {
REP #$20 TXY : LDX.b #$06
LDA.l GoalItemRequirement : BEQ .despawn REP #$30
LDA.l GanonVulnerableMode : AND.w #$00FF : CMP.w #$0005 : BEQ .despawn LDA.l GoalConditionTable, X
LDA.l TurnInGoalItems : AND.w #$00FF : BNE + TAX : LDA.l $B00000, X
SEP #$30
TYX
CMP.b #$00 : BEQ .despawn ; no goal, despawn
LDA.l TurnInGoalItems : BNE +
.despawn .despawn
SEP #$20
STZ.w SpriteAITable, X ; despawn self STZ.w SpriteAITable, X ; despawn self
RTS RTS
+ +
SEP #$20
LDA.b GameSubMode LDA.b GameSubMode
BNE .done BNE .done
LDA.b #$96 LDA.b #$96
LDY.b #$01 LDY.b #$01
JSL Sprite_ShowSolicitedMessageIfPlayerFacing_PreserveMessage : BCC .dont_show JSL Sprite_ShowSolicitedMessageIfPlayerFacing_PreserveMessage : BCC .dont_show
REP #$20 LDA.b #$03 : JSL CheckConditionPass : BCC +
LDA.l GoalCounter
CMP.l GoalItemRequirement : !BLT +
SEP #$20
JSL ActivateTriforceCutscene JSL ActivateTriforceCutscene
+ +
.dont_show .dont_show
.done .done
SEP #$20
LDA.b FrameCounter : LSR #5 : AND.b #$01 : STA.w SpriteGFXControl, X LDA.b FrameCounter : LSR #5 : AND.b #$01 : STA.w SpriteGFXControl, X
RTS RTS
} }

View File

@@ -107,8 +107,8 @@ RTL
;-------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------
OnAga1Defeated: OnAga1Defeated:
STA.l ProgressIndicator ; vanilla game state stuff we overwrote STA.l ProgressIndicator ; vanilla game state stuff we overwrote
LDA.l GanonVulnerableMode ; seems light_speed option to auto triforce room is unused for now
CMP.b #$06 : BNE + BRA +
.light_speed .light_speed
REP #$20 REP #$20
LDA.w #$0019 : STA.b GameMode LDA.w #$0019 : STA.b GameMode

View File

@@ -1,6 +1,6 @@
GoalItemGanonCheck: GoalItemGanonCheck:
LDA.w SpriteTypeTable, X : CMP.b #$D6 : BNE .success ; skip if not ganon LDA.w SpriteTypeTable, X : CMP.b #$D6 : BNE .success ; skip if not ganon
JSL CheckGanonVulnerability LDA.b #$01 : JSL CheckConditionPass
BCS .success BCS .success
.fail .fail
@@ -11,104 +11,162 @@ RTL
LDA.b OAMOffsetY : CMP.b #$80 ; thing we wrote over LDA.b OAMOffsetY : CMP.b #$80 ; thing we wrote over
RTL RTL
;-------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------
;Carry clear = ganon invincible ; Input A = Type of condition check
;Carry set = ganon vulnerable ; Carry clear = failed check
CheckGanonVulnerability: ; Carry set = successful check
PHX CheckConditionPass:
LDA.l GanonVulnerableMode PHX : PHY
ASL PHB
TAX 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 -
; Carry .exit
; 0 - invulnerable PLB : PLY : PLX
; 1 - vulnerable RTL
JSR (.goals, X)
PLX ; Y = index after condition code
RTL ; Carry = Set if using default target value
.conditions
dw .always_fail
.goals dw .pendants
dw .vulnerable
dw .invulnerable
dw .all_dungeons
dw .crystals_and_aga
dw .crystals dw .crystals
dw .pendant_bosses
dw .crystal_bosses
dw .bosses
dw .agahnim_defeated
dw .agahnim2_defeated
dw .goal_item dw .goal_item
dw .light_speed dw .collection_rate
dw .crystals_and_bosses dw .custom_goal
dw .bosses_only dw .bingo
dw .all_dungeons_no_agahnim dw .success
dw .all_items dw .success
dw .completionist dw .success
dw .success
; 00 = always vulnerable .agahnim2_defeated
.vulnerable LDA.l RoomDataWRAM[$0D].high : AND.b #$08 : BEQ .fail
.bingo ; not implemented yet
.success .success
SEC SEC : RTS
RTS .always_fail
; 01 = always invulnerable
.invulnerable
.fail .fail
CLC CLC : RTS
RTS .pendants
PHP
; 02 = All dungeons LDA.l PendantCounter : PLP : BCC +
.all_dungeons CMP.b #$03 : RTS
LDA.l ProgressIndicator : CMP.b #$03 : BCC .fail ; require post-aga world state
; 09 = All dungeons except agahnim
.all_dungeons_no_agahnim
LDA.l PendantsField : AND.b #$07 : CMP.b #$07 : BNE .fail ; require all pendants
LDA.l CrystalsField : AND.b #$7F : CMP.b #$7F : BNE .fail ; require all crystals
LDA.l RoomDataWRAM[$0D].high : AND.b #$08 : BEQ .fail ; require aga2 defeated (pyramid hole open)
BRA .success
; 03 = crystals and aga 2
.crystals_and_aga
LDA.l RoomDataWRAM[$0D].high : AND.b #$08 : BEQ .fail ; check aga2 first then bleed in
; 04 = crystals only
.crystals .crystals
JSL CheckEnoughCrystalsForGanon PHP
RTS LDA.l CrystalCounter : PLP : BCC +
CMP.b #$07 : RTS
; 05 = require goal item .pendant_bosses
PHP
LDA.b #$07 : STA.b Scrap03 : STZ.b Scrap04
JSR CheckForBossesDefeated : PLP : BCC +
CMP.b #$03 : RTS
.crystal_bosses
PHP
LDA.b #$40 : STA.b Scrap03 : STZ.b Scrap04
JSR CheckForBossesDefeated : PLP : BCC +
CMP.b #$07 : RTS
.bosses
PHP
LDA.b #$47 : STA.b Scrap03 : STZ.b Scrap04
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 .goal_item
REP #$20 REP #$20
LDA.l GoalCounter : CMP.l GoalItemRequirement LDA.l GoalCounter : BCC +
SEP #$20 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 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
; 06 = light speed ; --------------------------------------------------------------------------------
.light_speed ; Input A = Options value, see GoalConditionTable for format
BRA .fail ; 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)
; 07 = Crystals and bosses .comparisons
.crystals_and_bosses dw .minimum
JSL CheckEnoughCrystalsForGanon ; check crystals first then bleed in to next dw .exact
BCC .fail dw .bitfield_nonzero
dw .bitfield_match
; 08 = Crystal bosses but no crystals dw .count_bits
.bosses_only dw .fail
JMP CheckForCrystalBossesDefeated dw .fail
dw .fail
; 09 = 100% item collection rate
.all_items
REP #$20
LDA.l TotalItemCounter : CMP.l TotalItemCount
SEP #$20
RTS
; 0A = 100% item collection rate and all dungeons
.completionist
REP #$20
LDA.l TotalItemCounter : CMP.l TotalItemCount
SEP #$20
BCC .fail
BRA .all_dungeons
.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: GTCutscene_TransferGfx:
PHA PHA
@@ -203,47 +261,83 @@ GTCutscene_ActivateSparkle_SelectCrystal:
RTL RTL
;-------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------
GTCutscene_NumberOfCrystals: GTCutscene_NumberOfCrystals:
PHX : PHY : PHP
REP #$20 REP #$20
LDA.l GanonsTowerOpenAddress : CMP.w #CrystalCounter : BEQ + LDA.l GanonsTowerOpenGfx+2 : BEQ .not_multiple_gfx
LDA.w #$0001 : BRA .done LDX.b #$04
+ LDA.l GanonsTowerOpenTarget - LDA.l GanonsTowerOpenGfx, X : BEQ +
.done 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 SEP #$20
TAX
- LDA.l $B00000, X : CMP.b #$FF : BEQ .use_y
ROL : PHP : CMP.b #$10 : BCS .not_8bit_compare
; uses 8-bit targets
CMP.b #$04 : BNE .not_crystal_goal ; crystal goal
PLP : BCC +
LDY.b #$07 : BRA .use_y
.not_crystal_goal
CMP.b #$02 : BNE .not_pendant_goal ; pendant goal
PLP : BCC +
LDY.b #$03 : BRA .use_y
+
INX : LDA.l $B00000, X : TAY : BRA .use_y
.not_pendant_goal
PLP : INX : BCS +
INX
+
BRA -
.not_8bit_compare
CMP.b #$14 : BCS .custom_goal
; uses 16-bit targets
PLP : INX : BCS +
INX : INX
+
BRA -
.custom_goal
BNE .unknown
PLP
INC.b Scrap00
INX : LDA.l $B00000, X : BIT.b #$08 : PHP
INX : INX : INX : AND.b #$03 : BEQ .use_custom_target
INY
INX : PLP : BEQ +
INX
+
BRA -
.use_custom_target
PLP : BEQ .8bit_target
; 16-bit target
REP #$20
LDA.l $B00000, X : CMP.w #$0008 : SEP #$20 : INX : BRA +
.8bit_target
LDA.l $B00000, X : CMP.b #$08 : + : BCC +
INY : INX : BRA -
+
PHY : ADC.b 1,S : PLY : TAY
INX : JMP -
.unknown ; unknown condition, exit with safe value
PLP : INY
.use_y
TYA : CMP.b #$08 : BCC .done
LDA.b Scrap00
.done
PLP : PLY : PLX
RTS RTS
;-------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------
CheckEnoughCrystalsForGanon:
REP #$20
LDA.l CrystalCounter
CMP.l GanonVulnerableTarget
SEP #$20
RTL
;--------------------------------------------------------------------------------
CheckTowerOpen: CheckTowerOpen:
LDA.l GanonsTowerOpenMode : ASL : TAX LDA.b #$00 : JML CheckConditionPass
JSR (.tower_open_modes,X)
RTL
.tower_open_modes
dw .vanilla
dw .arbitrary_cmp
.vanilla
LDA.l CrystalsField
AND.b #$7F : CMP.b #$7F
RTS
.arbitrary_cmp
REP #$30
LDA.l GanonsTowerOpenAddress : TAX
LDA.l $7E0000,X
CMP.l GanonsTowerOpenTarget
SEP #$30
RTS
;--------------------------------------------------------------------------------------------------- ;---------------------------------------------------------------------------------------------------
CheckAgaForPed: CheckAgaForPed:
REP #$20 REP #$20
LDA.l GanonVulnerableMode ; seems light_speed option to force blue balls is unused for now
CMP.w #$0006 : BNE .vanilla BRA .vanilla
.light_speed .light_speed
SEP #$20 SEP #$20
@@ -264,7 +358,7 @@ CheckAgaForPed:
RTL RTL
;--------------------------------------------------------------------------------------------------- ;---------------------------------------------------------------------------------------------------
CheckForCrystalBossesDefeated: CheckForBossesDefeated:
PHB : PHX : PHY PHB : PHX : PHY
LDA.b #CrystalPendantFlags_2>>16 LDA.b #CrystalPendantFlags_2>>16
@@ -273,13 +367,13 @@ CheckForCrystalBossesDefeated:
REP #$30 REP #$30
; count of number of bosses killed ; count of number of bosses killed
STZ.b Scrap00 STZ.b Scrap04
LDY.w #10 LDY.w #10
.next_check .next_check
LDA.w CrystalPendantFlags_2+2,Y LDA.w CrystalPendantFlags_2+2,Y
BIT.w #$0040 BIT.w Scrap03
BEQ ++ BEQ ++
TYA TYA
@@ -293,7 +387,7 @@ CheckForCrystalBossesDefeated:
AND.w #$0800 AND.w #$0800
BEQ ++ BEQ ++
INC.b Scrap00 INC.b Scrap04
++ DEY ++ DEY
BPL .next_check BPL .next_check
@@ -301,36 +395,22 @@ CheckForCrystalBossesDefeated:
SEP #$30 SEP #$30
PLY : PLX : PLB PLY : PLX : PLB
LDA.b Scrap00 : CMP.l GanonVulnerableTarget LDA.b Scrap04
RTS RTS
;--------------------------------------------------------------------------------------------------- ;---------------------------------------------------------------------------------------------------
CheckPedestalPull: CheckPedestalPull:
; Out: c - Successful ped pull if set, do nothing if unset. ; Out: c - Successful ped pull if set, do nothing if unset.
PHX LDA.b #$02 : JSL CheckConditionPass : BCS .return
LDA.l PedCheckMode : ASL : TAX PHX : PHP
JSR (.pedestal_modes,X) LDA.b GameMode : CMP.b #$0E : BEQ +
PLX 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 RTL
.pedestal_modes
dw .vanilla
dw .arbitrary_cmp
.vanilla
LDA.l PendantsField
AND.b #$07 : CMP.b #$07 : BNE ..nopull
SEC
RTS
..nopull
CLC
RTS
.arbitrary_cmp
REP #$30
LDA.l PedPullAddress : TAX
LDA.l $7E0000,X
CMP.l PedPullTarget
SEP #$30
RTS

View File

@@ -892,43 +892,84 @@ org $B08196 ; PC 0x180196-0x180197
TotalItemCount: ; Total item count for HUD. Only counts items that use "item get" animation. TotalItemCount: ; Total item count for HUD. Only counts items that use "item get" animation.
dw $00D8 ; 216 dw $00D8 ; 216
org $B08198 ; PC 0x180198-0x1801A9 org $B08198 ; PC 0x180198-0x1801D7 (variable tables, $FF terminated)
GanonsTowerOpenAddress: ; 0x180198-0x180199 GoalConditionTable:
dw CrystalCounter ; Target address for GT open check dw GanonsTowerOpen
GanonsTowerOpenTarget: ; 0x18019A-0x18019B dw GanonVulnerable
dw $0007 ; Target amount for GT open modes to compare dw PedPull
GanonsTowerOpenMode: ; 0x18019C-0x18019D dw MurahdahlaComplete
dw $0001 ; $00 = Vanilla | $01 = Compare target with address
PedPullAddress: ; 0x18019E-0x18019F GanonsTowerOpen:
dw PendantCounter ; Target address for ped pull check db $82 ; Crystal Count >= Default 7
PedPullTarget: ; 0x1801A0-0x1801A1 db $FF
dw $0003 ; Target amount for ped pull modes to check GanonVulnerable:
PedCheckMode: ; 0x1801A2-0x1801A3 db $82 ; Crystal Count >= Default 7
dw $0000 ; $00 = vanilla | $01 = Compare address to target value db $07 ; Agahnim 2 defeated
GanonVulnerableAddress: ; 0x1801A4-0x1801A5 db $FF
dw CrystalCounter ; Target address for ped pull check PedPull:
GanonVulnerableTarget: ; 0x1801A6-0x1801A7 db $81 ; Pendant Count >= Default 3
dw $0007 ; Target amount for Ganon vulnerability modes to compare db $FF
GanonVulnerableMode: ; 0x1801A8-0x1801A9 MurahdahlaComplete:
dw $0000 ; #$00 = Off (default) db $88 ; Triforce Pieces >= Default Goal
; #$01 = On db $FF
; #$02 = Require All Dungeons ; These are lists of conditions to check for various goals,
; #$03 = Require "GanonVulnerableTarget" Crystals and Aga2 ; each terminated by #$FF.
; #$04 = Require "GanonVulnerableTarget" Crystals ; First byte is condition type, with most significant bit
; #$05 = Require "GoalItemRequirement" Goal Items ; indicating the default value should be used, else the
; #$06 = Light Speed ; following byte/s indicate the custom target value.
; #$07 = Require All Crystals and Crystal Bosses ; -----------------------------------------------------------
; #$08 = Require All Crystal Bosses only ; Condition Types:
; #$09 = Require All Dungeons No Agahnim ; #$00 = Always Invulnerable
; #$0A = Require 100% Item Collection ; #$01 = Require Pendants - Default is 3
; #$0B = Require 100% Item Collection and All Dungeons ; #$02 = Require Crystals - Default is 7
GanonsTowerOpenGfx: ; 0x1801AA-0x1801AB ; #$03 = Require Pendant Bosses - Default is 3
dw $0000 ; Gfx used for GT open animation, similar to StandingItemGraphicsOffsets ; #$04 = Require Crystal Bosses - Default is 7
GanonsTowerOpenPalette: ; 0x1801AC ; #$05 = Require Prize Bosses - Default is 10
db $00 ; Palette for GanonsTowerOpenGfx ; #$06 = Require Agahnim 1
;VHPP CCC O ; #$07 = Require Agahnim 2
; #$08 = Require Goal Items (ie. Triforce Pieces) - Default is value at GoalItemRequirement
; #$09 = Require Item Collection - Default is Max Collection Rate
; #$0A = Require Custom Goal
; -----------------------------------------------------------
; For Custom Goal, one byte indicates the bitfield options,
; followed by two bytes for the target address, followed
; by one or two bytes for the custom target value.
; Options bitfield:
; ---b accc
; b - bank flag - 0 = $7E - 1 = $7F
; a - addressing mode - 0 = 8-bit - 1 = 16-bit
; c - comparison mode
; 0 = minimum (>=)
; 1 = exact (==)
; 2 = bitfield any
; 3 = bitfield match
; 4 = count bits set in bitfield
; 5-7 = reserved
;-------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------
; 0x1801AD - 0x1801FF (unused) org $B081D8 ; PC 0x1801D8 - 0x1801FE
GanonsTowerOpenGfx: ; 0x1801D8-0x1801E5
dw $0000 ; Gfx used for GT open animation, similar to StandingItemGraphicsOffsets
dw $0000, $0000, $0000, $0000, $0000, $0000
GanonsTowerOpenPalette: ; 0x1801E6-0x1801EC
db $00 ; Palette for GanonsTowerOpenGfx
db $00, $00, $00, $00, $00, $00
; VHPP CCCO (VertFlip, HorizFlip, Priority, ColorPalette, OAM Sheet)
PedPullGfx: ; 0x1801ED-0x1801F2
dw $0000 ; Gfx used for ped pull animation, similar to StandingItemGraphicsOffsets
dw $0000, $0000
PedPullPalette: ; 0x1801F3-0x1801F5
db $00 ; Palette for PedPullGfx
db $00, $00
; VHPP CCCO (VertFlip, HorizFlip, Priority, ColorPalette, OAM Sheet)
MurahdahlaGfx: ; 0x1801F6-0x1801FB
dw $0000 ; Gfx used for ped pull animation, similar to StandingItemGraphicsOffsets
dw $0000, $0000
MurahdahlaPalette: ; 0x1801FC-0x1801FE
db $00 ; Palette for MurahdahlaGfx
db $00, $00
; VHPP CCCO (VertFlip, HorizFlip, Priority, ColorPalette, OAM Sheet)
;--------------------------------------------------------------------------------
; 0x1801FF (unused)
;================================================================================ ;================================================================================
org $B08200 ; PC 0x180200 - 0x18020B org $B08200 ; PC 0x180200 - 0x18020B
RedClockAmount: RedClockAmount:

View File

@@ -520,3 +520,20 @@ AuxPaletteCheck:
REP #$30 REP #$30
PLX PLX
RTS RTS
CountBits:
; In: A - value to count bits set in
; Out: A - number of bits set
; Flexible to use with 8 or 16-bit mode
PHX : TAX
PHY : PHP
SEP #$20
LDA.b 1,S : BIT.b #$20 : BNE +
PLP : TXA : LDX.w #$000F : LDY.w #$0000
BRA ++
+ PLP : TXA : LDX.b #$07 : LDY.b #$00
++ - LSR : BCC +
INY
+ DEX : BPL -
TYA : PLY : PLX
RTL