Files
oracle-of-secrets/Sprites/NPCs/followers.asm
Jared_Brian_ e112bed264 Made it so the minecart sprite to follower to sprite hand off is much smoother by telling the old sprite cart not to draw after the follower spawns, adjusting the positioning of the follower draw itself, and also made it so it won't always be vertical
Fixed the bug that made it so the minecart would auto grab you sometimes after getting off
and then there was another bug that had accidently been introduced that made carts on track 00 not work
2025-02-01 19:08:57 -07:00

1060 lines
22 KiB
NASM

; =========================================================
; Followers
; 20 steps of animation and movement caching for followers
FollowerYL = $7E1A00
FollowerYH = $7E1A14
FollowerXL = $7E1A28
FollowerXH = $7E1A3C
FollowerZ = $7E1A50
FollowerLayer = $7E1A64
; Follower head/body gfx offsets
; Down:0x00 LR:0x80 Up:0x20
FollowerHeadOffset = $7E0AE8
FollowerHeadOffsetH = $7E0AE9
; Walk LR:0x60,0x80 0xA0:Down 0xC0:Up
FollowerBodyOffset = $7E0AEA
FollowerBodyOffsetH = $7E0AEB
Follower_WatchLink:
{
JSL Sprite_IsToRightOfPlayer : TYA : BEQ .right
LDA.b #$40 : STA.w FollowerHeadOffset
LDA.b #$60 : STA.w FollowerBodyOffset
RTS
.right
LDA.b #$00 : STA.w FollowerHeadOffset
LDA.b #$A0 : STA.w FollowerBodyOffset
RTS
}
; Follower head
Flwhgfxt = $7E0AEC
Flwhgfxth = $7E0AED
Flwhgfxb = $7E0AEE
Flwhgfxbh = $7E0AEF
; Follower body
Flwbgfxt = $7E0AF0
Flwbgfxth = $7E0AF1
Flwbgfxb = $7E0AF2
Flwbgfxbh = $7E0AF3
; Index from 0x00 to 0x13 for follower animation step index. Used for reading data.
Flwanimir = $7E02CF
; Flag set when using hookshot with a follower. Forces game mode check.
FollowerHook = $7E02D0
; Caches FLWANIMIW when hookshotting is finished.
FollowerHookI = $7E02D1
; Countdown timer preventing followers from being regrabbed after dropping for a brief period.
FLWGRABTIME = $7E02D2
; Index from 0x00 to 0x13 for follower animation step index. Used for writing data.
FLWANIMIW = $7E02D3
; Cache of follower properties
FollowCacheYL = $7EF3CD
FollowCacheYH = $7EF3CE
FollowCacheXL = $7EF3CF
FollowCacheXH = $7EF3D0
LoadFollowerGraphics = $00D423
; org $099F99
; #Follower_AIVectors:
; Follower_BasicMover ; 0x01 - Zelda (Impa)
; Follower_OldMan ; 0x02 - Old man that stops following you
; Follower_OldManUnused ; 0x03 - Unused old man
; Follower_OldMan ; 0x04 - Normal old man
; Follower_Telepathy ; 0x05 - Zelda rescue telepathy
; Follower_BasicMover ; 0x06 - Blind maiden
; Follower_BasicMover ; 0x07 - Frogsmith
; Follower_BasicMover ; 0x08 - Smithy
; Follower_BasicMover ; 0x09 - Locksmith (Zora Baby)
; Follower_BasicMover ; 0x0A - Kiki
; Follower_OldManUnused ; 0x0B - Minecart Follower
; Follower_BasicMover ; 0x0C - Purple chest
; Follower_BasicMover ; 0x0D - Super bomb
; Follower_Telepathy ; 0x0E - Master Sword telepathy
; =========================================================
; Zora Baby Follower Sprite
; Uses Sprite 0x39 Locksmith in Bank06
ZoraBaby_RevertToSprite:
{
PHA
LDA.b #$39 : JSL Sprite_SpawnDynamically
PLA
PHX
TAX
LDA.w $1A64, X : AND.b #$03 : STA.w SprMiscE, Y : STA.w SprMiscC, Y
LDA.w $1A00, X : CLC : ADC.b #$02 : STA.w SprY, Y
LDA.w $1A14, X : ADC.b #$00 : STA.w SprYH, Y
LDA.w $1A28, X : CLC : ADC.b #$10 : STA.w SprX, Y
LDA.w $1A3C, X : ADC.b #$00 : STA.w SprXH, Y
LDA.b $EE : STA.w $0F20, Y
LDA.b #$01 : STA.w SprBulletproof, Y : STA.w $0E80, Y
LDA.b #$04 : STA.w SprAction, Y
LDA.b #$FF : STA.w SprTimerB, Y
PLX
LDA.b #$00 : STA.l $7EF3CC
STZ.b $5E
RTS
}
CheckForZoraBabyTransitionToSprite:
{
LDA.l $7EF3CC : CMP.b #$09 : BNE .not_zora
; If we are standing on a star tile
LDA.w $0114 : CMP.b #$3B : BNE +
LDA.b #$00
JSR ZoraBaby_RevertToSprite
+
; If we are outdoors, clear the follower
LDA.b $1B : BNE +
LDA.b #$00 : STA.l $7EF3CC
+
.not_zora
LDX.b $10
LDY.b $11
RTL
}
CheckForZoraBabyFollower:
{
LDA.l $7EF3CC : CMP.b #$09 : BNE .not_zora
LDA.b #$00
RTL
.not_zora
LDA.b $05
AND.b #$20
RTL
}
UploadZoraBabyGraphicsPrep:
{
PHX
LDA.b #$09 : STA.l $7EF3CC
LDA.b #$A0 : STA.w $0AEA
JSL $00D423
LDA.b #$00 : STA.l $7EF3CC
PLX
LDA.b #$02 : STA.w SprAction, X
LDA.l $7EF3C9
RTL
}
; =========================================================
; Check if the Zora baby is on top of the water gate switch
; Returns carry set if the Zora baby is on top of the switch
ZoraBaby_CheckForWaterSwitchSprite:
{
PHX
LDX #$10
-
LDA.w SprType, X
CMP #$21 : BEQ ZoraBaby_CheckForWaterGateSwitch_found_switch
DEX : BPL -
; Water gate switch not found
PLX
.not_on_switch
CLC
RTS
}
ZoraBaby_CheckForWaterGateSwitch:
{
PHX
LDX #$10
-
LDA.w SprType, X : CMP #$04 : BEQ .found_switch
DEX : BPL -
; Water gate switch not found
PLX
.not_on_switch
CLC
RTS
.found_switch
TXY
PLX
; X is the Zora baby Sprite
; Y is the Water gate switch Sprite
; Check if the Zora baby is on top of the switch
LDA.w SprX, X : CLC : ADC #$09 : CMP.w SprX, Y : BCC .not_on_switch
LDA.w SprX, X : SEC : SBC #$09 : CMP.w SprX, Y : BCS .not_on_switch
LDA.w SprY, X : CLC : ADC #$12 : CMP.w SprY, Y : BCC .not_on_switch
LDA.w SprY, X : SEC : SBC #$12 : CMP.w SprY, Y : BCS .not_on_switch
SEC
RTS
}
ZoraBaby_GlobalBehavior:
{
JSL Sprite_BehaveAsBarrier
JSR Follower_WatchLink
LDA.w SprAction, X : CMP.b #$02 : BEQ +
JSL Sprite_CheckIfLifted
JSL ThrownSprite_TileAndSpriteInteraction_long
JSL Sprite_Move
JSR ZoraBaby_CheckForWaterGateSwitch : BCC ++
; Face head up towards switch
LDA.b #$20 : STA.w FollowerHeadOffset
; Set end of switch graphics
LDA.b #$0D : STA.w SprGfx, Y
; Set the water gate tag
LDA.b #$01 : STA.w $0642
; Goto ZoraBaby_PullSwitch
LDA.b #$05 : STA.w SprAction, X
++
JSR ZoraBaby_CheckForWaterSwitchSprite : BCC +
; Set end of switch graphics
LDA.b #$01 : STA.w SprAction, Y
; Goto ZoraBaby_PullSwitch
LDA.b #$05 : STA.w SprAction, X
LDA.w SprX, X : CLC : ADC #$10 : STA.w SprX, X
+
RTL
}
pushpc
; Make Zora sway like a girl
org $09AA5E : JSL CheckForZoraBabyFollower
; Follower_BasicMover
; Jump to ZoraBaby sprite on star tile
org $09A19C : JSL CheckForZoraBabyTransitionToSprite
; Make Zora follower blue palette
org $09A902 : db $02
; Zora Baby char data offset
org $09A8CF : org $00C0
; Zora Baby Sprite Idle OAM data
org $06BD9C
dw 0, -8 : db $20, $03, $00, $02
dw 0, 0 : db $22, $03, $00, $02
org $068D59
SpritePrep_Locksmith:
{
INC.w SprBulletproof, X
; Clear sprite if we already have Zora baby
LDA.l $7EF3CC : CMP.b #$09 : BNE .not_already_following
STZ.w SprState, X
RTS
.not_already_following
CMP.b #$0C : BNE .no_purple_chest
LDA.b #$02 : STA.w SprAction, X
.no_purple_chest
JSL UploadZoraBabyGraphicsPrep : AND.b #$10 : BEQ .exit
LDA.b #$04 : STA.w SprAction, X
.exit
RTS
}
assert pc() <= $068D7F
SpriteDraw_Locksmith = $06BDAC
Sprite_CheckIfActive_Bank06 = $06D9EC
; Overrides Sprite_39_Locksmith
org $06BCAC
Sprite_39_ZoraBaby:
{
JSR SpriteDraw_Locksmith
JSR Sprite_CheckIfActive_Bank06
JSL ZoraBaby_GlobalBehavior
LDA.w SprAction, X
JSL JumpTableLocal
dw LockSmith_Chillin
dw ZoraBaby_FollowLink ; Becomes Follower
dw ZoraBaby_OfferService ; I can help! (Follow/Stay)
dw ZoraBaby_RespondToAnswer ; Goto FollowLink or JustPromiseOkay
dw ZoraBaby_AgreeToWait
dw ZoraBaby_PullSwitch
dw ZoraBaby_PostSwitch
; =======================================================
LockSmith_Chillin:
{
LDY.b #$01 : LDA.b #$07 ; MESSAGE 0107
JSL Sprite_ShowSolicitedMessage
LDA.w SprX, X
PHA
SEC : SBC.b #$10 : STA.w SprX, X
JSR Sprite_Get16BitCoords_Local
LDA.b #$01 : STA.w SprXSpeed, X : STA.w SprYSpeed, X
JSL Sprite_CheckTileCollision_long : BNE .dont_stalk_link
INC.w SprAction, X
LDA.l $7EF3CC : CMP.b #$00 : BEQ .dont_stalk_link
LDA.b #$05 : STA.w SprAction, X
.dont_stalk_link
PLA
STA.w SprX, X
RTS
}
; =======================================================
ZoraBaby_FollowLink:
{
LDA.b #$09 : STA.l $7EF3CC
PHX
STZ.w $02F9
JSL LoadFollowerGraphics
JSL Follower_Initialize
PLX
LDA.b #$40
STA.w $02CD
STZ.w $02CE
STZ.w SprState, X
RTS
}
; =======================================================
ZoraBaby_OfferService:
{
JSL CheckIfLinkIsBusy : BCS .exit
LDY.b #$01 : LDA.b #$09 ; MESSAGE 0109
JSL Sprite_ShowSolicitedMessage : BCC .exit
INC.w SprAction, X
.exit
RTS
}
; =======================================================
ZoraBaby_RespondToAnswer:
{
LDA.w $1CE8 : BNE .rejected
LDY.b #$01 : LDA.b #$0C ; MESSAGE 010C
JSL Sprite_ShowMessageUnconditional
LDA.b #$01 : STA.w SprAction, X
RTS
; LDA.l $7EF3C9
; ORA.b #$10
; STA.l $7EF3C9
.rejected
LDY.b #$01 : LDA.b #$0A ; MESSAGE 010A
JSL Sprite_ShowMessageUnconditional
LDA.b #$FF : STA.w SprTimerB, X
INC.w SprAction, X
RTS
}
; =======================================================
ZoraBaby_AgreeToWait:
{
LDA.b #$A0 : STA.w $0AEA
LDY.b #$01 : LDA.b #$0B ; MESSAGE 010B
JSL Sprite_ShowSolicitedMessage
LDA.w SprTimerB, X : BNE +
STZ.w SprAction, X
+
RTS
}
; =======================================================
ZoraBaby_PullSwitch:
{
LDY.b #$01 : LDA.b #$07 ; MESSAGE 0107
JSL Sprite_ShowMessageUnconditional
; LDA.b #$01 : STA.b $B1
; JSL $01B8BF
INC.w SprAction, X
RTS
}
ZoraBaby_PostSwitch:
{
RTS
}
}
print "End of Sprite 39 Locksmith ", pc
assert pc() <= $06BD9C
pullpc
; =========================================================
; Old Man Follower Sprite
; Old man sprite wont spawn in his home room
; if you have the follower
OldMan_ExpandedPrep:
{
; ROOM 00E4
LDA.l $7EF3CC : CMP.b #$04 : BEQ .not_home
LDA.b $A0 : CMP.b #$E4 : BNE .not_home
CLC
RTL
.not_home
SEC
RTL
}
pushpc
; Old man gives link the "shovel"
; Now the goldstar hookshot upgrade
org $1EE9FF : LDY.b #$13 : STZ.w $02E9
; FindEntrance
org $1BBD3C : CMP.w #$04
; Underworld_LoadEntrance
org $02D98B : CMP.w #$02
org $1EE8F1
SpritePrep_OldMan:
{
PHB : PHK : PLB
JSR .main
PLB
RTL
.main
INC.w SprBulletproof, X
JSL OldMan_ExpandedPrep : BCS .not_home
LDA.b #$02 : STA.w $0E80, X
RTS
.not_home
LDA.l $7EF3CC : CMP.b #$00 : BNE .dont_spawn
; Check for lv2 hookshot instead of mirror
LDA.l $7EF342 : CMP.b #$02 : BNE .spawn
STZ.w SprState, X
.spawn
; FOLLOWER 04
LDA.b #$04 : STA.l $7EF3CC
PHX
JSL LoadFollowerGraphics
PLX
LDA.b #$00 : STA.l $7EF3CC
RTS
.dont_spawn
STZ.w SprState, X
PHX
JSL LoadFollowerGraphics
PLX
RTS
}
org $09A4C8
Follower_HandleTriggerData:
{
.room_id
dw $00D1 ; ROOM 00D1 - old man cave
dw $00FE ; ROOM 0061 - castle lobby
dw $00FD ; ROOM 0051 - castle throne room
dw $00FD ; ROOM 0002 - pre-sanc
dw $00DB ; ROOM 00DB - TT entrance
dw $00AB ; ROOM 00AB - to TT attic
dw $0022 ; ROOM 0022 - sewer rats
.coordinates_uw
dw $1A78, $0233, $0001, $0099, $0004 ; Old man - MESSAGE 0099
dw $1BC0, $0378, $0002, $009A, $0004 ; Old man - MESSAGE 009A
dw $1A78, $0378, $0004, $009B, $0004 ; Old man - MESSAGE 009B
dw $1FF8, $039D, $0001, $0021, $0001 ; Zelda - MESSAGE 0021
dw $1FF8, $039D, $0002, $0021, $0001 ; Zelda - MESSAGE 0021
dw $1FF8, $0238, $0004, $0021, $0001 ; Zelda - MESSAGE 0021
dw $1D78, $1F7F, $0001, $0022, $0001 ; Zelda - MESSAGE 0022
dw $1D78, $1F7F, $0001, $0023, $0001 ; Zelda - MESSAGE 0023
dw $1D78, $1F7F, $0002, $002A, $0001 ; Zelda - MESSAGE 002A
dw $1BD8, $16FC, $0001, $0124, $0006 ; Blind maiden - MESSAGE 0124
dw $1520, $167C, $0001, $0124, $0006 ; Blind maiden - MESSAGE 0124
dw $05AC, $04FC, $0001, $0029, $0001 ; Zelda - MESSAGE 0029
; -------------------------------------------------------
.overworld_id
dw $0005 ; OW 05 - West DM (Updated)
dw $002F ; OW 2F - Tail Palace
dw $0000 ; OW 00 - Lost woods
.coordinates_ow
dw $0178, $0A63, $0001, $009D, $0004 ; Old man - MESSAGE 009D
; Y X
dw $0A88, $0F41, $0000, $FFFF, $000A ; Kiki
dw $0B37, $0F40, $0001, $FFFF, $000A ; Kiki
dw $0A62, $0E5B, $0002, $FFFF, $000A ; Kiki
dw $00E8, $0090, $0000, $0028, $000E ; MS telepathy - MESSAGE 0028
; -------------------------------------------------------
.room_boundaries_check
dw $0000, $001E, $003C, $0046
dw $005A, $0064, $006E, $0078
.ow_boundaries_check
dw $0000, $000A, $0028, $0032
}
pullpc
Kiki_CheckIfScared:
{
; If Links health is too low, kiki will run away from him
; rather than when he takes damage as it currently is.
LDA.b $4D : BEQ .not_scared
LDA.w $031F : BEQ .not_scared
LDA.l $7EF36D : CMP.b #$02 : BNE .not_scared
SEC
RTL
.not_scared
CLC
RTL
}
pushpc
; Kiki
dont_scare_kiki = $09A1E4
org $09A1C6
JSL Kiki_CheckIfScared
BCC dont_scare_kiki
NOP #3
; TODO: Update Kiki jump pos
org $1EE2E9
Kiki_WalkOnRoof:
.speed_x ; bleeds into next
db 0, 0
.speed_y
db -9, 9, 0, 0
org $1EE576
Kiki_HopToSpot:
.target_y
dw $0661
dw $064C
dw $0624
.target_x
dw $0F4F
dw $0F70
dw $0F5D
org $1EE5E9
Kiki_WalkOnRoof_Ext:
.step
db $02, $01, $FF
.timer
db 82, 0
pullpc
; =========================================================
; Minecart Follower Sprite
FollowerDraw_CalculateOAMCoords:
{
REP #$20
LDA.b $02 : STA.b ($90), Y
INY
CLC : ADC.w #$0080 : CMP.w #$0180 : BCS .off_screen
LDA.b $02 : AND.w #$0100 : STA.b $74
LDA.b $00 : STA.b ($90), Y
CLC : ADC.w #$0010 : CMP.w #$0100 : BCC .on_screen
.off_screen:
LDA.w #$00F0 : STA.b ($90), Y
.on_screen:
SEP #$20
INY
RTS
}
MinecartFollower_Top:
{
SEP #$30
JSR FollowerDraw_CalculateOAMCoords
LDA #$08
JSL OAM_AllocateFromRegionB
LDA $02CF : TAY
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ; amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile index
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset
ASL A : TAX
REP #$20
LDA $02 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $00 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA.b #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index:
db $00, $02, $04, $06
.nbr_of_tiles:
db 1, 1, 1, 1
.x_offsets:
dw -8, 8
dw -8, 8
dw -8, 8
dw -8, 8
.y_offsets:
dw -12, -12
dw -11, -11
dw -8, -8
dw -7, -7
.chr:
db $40, $40
db $40, $40
db $42, $42
db $42, $42
.properties:
db $3D, $7D
db $3D, $7D
db $3D, $7D
db $3D, $7D
}
MinecartFollower_Bottom:
{
SEP #$30
JSR FollowerDraw_CalculateOAMCoords
LDA #$08
JSL OAM_AllocateFromRegionC
LDA $02CF : TAY
LDA .start_index, Y : STA $06
PHX
LDX .nbr_of_tiles, Y ; amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $02 : CLC : ADC .x_offsets, X : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $00 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA.b #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
.start_index:
db $00, $02, $04, $06
.nbr_of_tiles:
db 1, 1, 1, 1
.x_offsets:
dw -8, 8
dw -8, 8
dw -8, 8
dw -8, 8
.y_offsets:
dw 4, 4
dw 5, 5
dw 8, 8
dw 9, 9
.chr:
db $60, $60
db $60, $60
db $62, $62
db $62, $62
.properties:
db $3D, $7D
db $3D, $7D
db $3D, $7D
db $3D, $7D
}
Minecart_AnimDirection:
db $02, $00, $02, $00
MinecartFollower_TransitionToSprite:
{
LDA.b #$A3
JSL Sprite_SpawnDynamically
TYX
JSL Sprite_SetSpawnedCoords
LDA.w !MinecartDirectionCache : STA.w !MinecartDirection, X
CMP.b #$00 : BEQ .vert_adjust
CMP.b #$02 : BEQ .vert_adjust
LDA.w POSY : CLC : ADC #$08 : STA.w SprY, X
LDA.w POSX : STA.w SprX, X
JMP .finish_prep
.vert_adjust
LDA.w POSY : STA.w SprY, X
LDA.w POSX : CLC : ADC #$02 : STA.w SprX, X
.finish_prep
LDA.w POSYH : STA.w SprYH, X
LDA.w POSXH : STA.w SprXH, X
LDA.w !MinecartDirection, X
CLC : ADC.b #$04 : STA.w SprMiscB, X
; Tell the newly spawned cart which track it is on.
LDA.w !MinecartTrackCache : STA.w SprSubtype, X
LDA Minecart_AnimDirection, X : STA $0D90, X
JSL Sprite_Minecart_Prep
LDA.b #$00 : STA.l $7EF3CC
RTL
}
; Minecart Follower Main Routine and Draw
DrawMinecartFollower:
{
JSL $099EFC ; Follower_Initialize
LDA.w !MinecartDirectionCache : TAX
LDA Minecart_AnimDirection, X : STA $02CF
JSR FollowerDraw_CachePosition
JSR MinecartFollower_Top
JSR MinecartFollower_Bottom
; Check the current submodule in the underworld
LDA.b $11 : BNE .dont_spawn
LDA !LinkInCart : BEQ .dont_spawn
;LDA.b #$09 : STA.b LinkState
JSL MinecartFollower_TransitionToSprite
.dont_spawn
RTS
}
FollowerDraw_CachePosition:
{
LDX.b #$00
LDA.w $1A00, X : STA.b $00
LDA.w $1A14, X : STA.b $01
LDA.w $1A28, X : STA.b $02
LDA.w $1A3C, X : STA.b $03
LDA.w $1A64, X : STA.b $05
; Adjust the coordinate a bit to place it more in line where the
; minecart should be relative to Link.
REP #$20
LDA.b $00 : SEC : SBC.w #$0008 : STA.b $00
LDA.b $02 : CLC : ADC.w #$0002 : STA.b $02
SEP #$20
; -------------------------
AND.b #$20
LSR A
LSR A
TAY
LDA.b $05
AND.b #$03
STA.b $04
STZ.b $72
; Vanilla game would check some priority and collision
; variables based on the follower here and manipulate $72
; if the player was immobile.
CLC : ADC $04 : STA $04
TYA : CLC : ADC $04 : STA $04
; -------------------------
REP #$20
LDA $0FB3 : AND.w #$00FF : ASL A : TAY
LDA $20 : CMP $00 : BEQ .check_priority_for_region
BCS .use_region_b
BRA .use_region_a
.check_priority_for_region
LDA $05 : AND.w #$0003 : BNE .use_region_b
.use_region_a
LDA.w .oam_region_offsets_a, Y
BRA .set_region
.use_region_b
LDA.w .oam_region_offsets_b, Y
.set_region
PHA
LSR #2 : CLC : ADC.w #$0A20 : STA $92
PLA : CLC : ADC.w #$0800 : STA $90
LDA $00 : SEC : SBC $E8 : STA $06
LDA $02 : SEC : SBC $E2 : STA $08
SEP #$20
LDA.w $02D7
INC A
CMP.b #$03
BNE .set_repri
LDA.b #$00
.set_repri
STA.w $02D7
LDA $02D7 : ASL #2 : STA $05
TXA : CLC : ADC $05 : TAX
REP #$20
LDA $06 : CLC : ADC.w #$0010 : STA $00
LDA $08 : STA $02
STZ $74
SEP #$20
RTS
.oam_region_offsets_a
dw $0170
dw $00C0
.oam_region_offsets_b
dw $01C0
dw $0110
}
CheckForMinecartFollowerDraw:
{
PHB : PHK : PLB
LDA.l $7EF3CC : CMP.b #$0B : BNE .not_minecart
JSR DrawMinecartFollower
.not_minecart
; LDA.b #$10 : STA.b $5E
PLB
RTL
}
CheckForFollowerInterroomTransition:
{
LDA.w !LinkInCart : BEQ .not_in_cart
LDA.b #$0B : STA $7EF3CC
; Pause the current cart so that it doesn't draw anymore
PHX
LDX.w !MinecartCurrent
LDA.b #$01 : STA $0F00, X
PLX
.not_in_cart
JSL $01873A ; Underworld_LoadRoom
RTL
}
CheckForFollowerIntraroomTransition:
{
STA.l $7EC007
LDA.w !LinkInCart : BEQ .not_in_cart
LDA.b #$0B : STA $7EF3CC
.not_in_cart
RTL
}
; 0x09
LinkState_Minecart:
{
PHB : PHK : PLB
STZ.b $2A
STZ.b $2B
STZ.b $6B
STZ.b $48
; Move Link based on the direction of the cart
LDA.w !MinecartDirection, X : BNE .not_north
LDY.b #$00
LDA.w .drag_y_low, Y : CLC : ADC.w $0B7E : STA.w $0B7E
LDA.w .drag_y_high, Y : ADC.w $0B7F : STA.w $0B7F
STZ.w LinkFaceDir
.not_north
CMP.b #$01 : BNE .not_east
LDY #$03
LDA.w .drag_x_low, Y : CLC : ADC.w DragYL : STA.w DragYL
LDA.w .drag_x_high, Y : ADC.w DragYH : STA.w DragYH
LDA.b #$06 : STA.w LinkFaceDir
.not_east
CMP.b #$02 : BNE .not_south
LDY #$01
LDA.w .drag_y_low, Y : CLC : ADC.w $0B7E : STA.w $0B7E
LDA.w .drag_y_high, Y : ADC.w $0B7F : STA.w $0B7F
LDA.b #$02 : STA.w LinkFaceDir
.not_south
CMP.b #$03 : BNE .not_west
LDY #$02
LDA.w .drag_x_low, Y : CLC : ADC.w DragYL : STA.w DragYL
LDA.w .drag_x_high, Y : ADC.w DragYH : STA.w DragYH
.not_west
JSL Link_HandleCardinalCollision_Long
JSL Link_HandleVelocityAndSandDrag
STZ.w $0302
; JSL Link_HandleMovingAnimation_FullLongEntry
JSL HandleIndoorCameraAndDoors
JSL Link_CancelDash
; Pos - Cache Pos = difference
LDA.w LinkX : SEC : SBC $3F : STA $31
LDA.w LinkY : SEC : SBC $3E : STA $30
PLB
RTL
.drag_x_high
db 0, 0, -1, 0
.drag_x_low
db 0, 0, -1, 1
.drag_y_low
db -1, 1, 0, 0
.drag_y_high
db -1, 0, 0, 0
}
pushpc
org $07A5F7
JSL LinkState_Minecart
RTS
assert pc() <= $07A64B
; Minecart Track tile types
org $07D938
dw TileBehavior_Nothing ; 0xB0 UW LR
dw TileBehavior_Nothing ; 0xB1 UW UD
dw TileBehavior_Nothing ; 0xB2 UW TL
dw TileBehavior_Nothing ; 0xB3 UW BL
dw TileBehavior_Nothing ; 0xB4 UW TR
dw TileBehavior_Nothing ; 0xB5 UW BR
dw TileBehavior_Nothing ; 0xB6 UW Any
dw TileBehavior_Nothing ; 0xB7 UW Stop Top
dw TileBehavior_Nothing ; 0xB8 UW Stop Bottom
dw TileBehavior_Nothing ; 0xB9 UW Stop Left
dw TileBehavior_Nothing ; 0xBA UW Stop Right
dw TileBehavior_Nothing ; TileBehavior_Pit ; 0xBB UW Pit LR
dw TileBehavior_Nothing ; TileBehavior_Pit ; 0xBC UW Pit UD
dw TileBehavior_Nothing ; TileBehavior_Pit ; 0xBD UW Any
; Follower_OldManUnused
org $09A41F
JSL CheckForMinecartFollowerDraw
RTS
; Module07_02_01_LoadNextRoom
org $028A5B : JSL CheckForFollowerInterroomTransition
; UnderworldTransition_Intraroom_PrepTransition
org $0289BF : JSL CheckForFollowerIntraroomTransition
pullpc