ref: 14c8cf5b4817d1cb5446349bd04949186f73093c
dir: /engine/player_movement.asm/
DoPlayerMovement:: ; 80000 call .GetDPad ld a, movement_step_sleep ld [MovementAnimation], a xor a ld [wd041], a call .TranslateIntoMovement ld c, a ld a, [MovementAnimation] ld [wPlayerNextMovement], a ret .GetDPad: ld a, [hJoyDown] ld [CurInput], a ; Standing downhill instead moves down. ld hl, wBikeFlags bit 2, [hl] ; downhill ret z ld c, a and D_PAD ret nz ld a, c or D_DOWN ld [CurInput], a ret ; 8002d .TranslateIntoMovement: ld a, [PlayerState] cp PLAYER_NORMAL jr z, .Normal cp PLAYER_SURF jr z, .Surf cp PLAYER_SURF_PIKA jr z, .Surf cp PLAYER_BIKE jr z, .Normal cp PLAYER_SKATE jr z, .Ice .Normal: call .CheckForced call .GetAction call .CheckTile ret c call .CheckTurning ret c call .TryStep ret c call .TryJump ret c call .CheckWarp ret c jr .NotMoving .Surf: call .CheckForced call .GetAction call .CheckTile ret c call .CheckTurning ret c call .TrySurf ret c jr .NotMoving .Ice: call .CheckForced call .GetAction call .CheckTile ret c call .CheckTurning ret c call .TryStep ret c call .TryJump ret c call .CheckWarp ret c ld a, [WalkingDirection] cp STANDING jr z, .HitWall call .BumpSound .HitWall: call .StandInPlace xor a ret .NotMoving: ld a, [WalkingDirection] cp STANDING jr z, .Standing ; Walking into an edge warp won't bump. ld a, [EngineBuffer4] and a jr nz, .CantMove call .BumpSound .CantMove: call ._WalkInPlace xor a ret .Standing: call .StandInPlace xor a ret ; 800b7 .CheckTile: ; 800b7 ; Tiles such as waterfalls and warps move the player ; in a given direction, overriding input. ld a, [PlayerStandingTile] ld c, a call CheckWhirlpoolTile jr c, .not_whirlpool ld a, 3 scf ret .not_whirlpool and $f0 cp HI_NYBBLE_CURRENT jr z, .water cp HI_NYBBLE_WALK jr z, .land1 cp HI_NYBBLE_WALK_ALT jr z, .land2 cp HI_NYBBLE_WARPS jr z, .warps jr .no_walk .water ld a, c maskbits NUM_DIRECTIONS +- 1 ld c, a ld b, 0 ld hl, .water_table add hl, bc ld a, [hl] ld [WalkingDirection], a jr .continue_walk .water_table db RIGHT ; COLL_WATERFALL_RIGHT db LEFT ; COLL_WATERFALL_LEFT db UP ; COLL_WATERFALL_UP db DOWN ; COLL_WATERFALL .land1 ld a, c and 7 ld c, a ld b, 0 ld hl, .land1_table add hl, bc ld a, [hl] cp STANDING jr z, .no_walk ld [WalkingDirection], a jr .continue_walk .land1_table db STANDING ; COLL_BRAKE db RIGHT ; COLL_WALK_RIGHT db LEFT ; COLL_WALK_LEFT db UP ; COLL_WALK_UP db DOWN ; COLL_WALK_DOWN db STANDING ; COLL_BRAKE_45 db STANDING ; COLL_BRAKE_46 db STANDING ; COLL_BRAKE_47 .land2 ld a, c and 7 ld c, a ld b, 0 ld hl, .land2_table add hl, bc ld a, [hl] cp STANDING jr z, .no_walk ld [WalkingDirection], a jr .continue_walk .land2_table db RIGHT ; COLL_WALK_RIGHT_ALT db LEFT ; COLL_WALK_LEFT_ALT db UP ; COLL_WALK_UP_ALT db DOWN ; COLL_WALK_DOWN_ALT db STANDING ; COLL_BRAKE_ALT db STANDING ; COLL_BRAKE_55 db STANDING ; COLL_BRAKE_56 db STANDING ; COLL_BRAKE_57 .warps ld a, c cp COLL_DOOR jr z, .down cp COLL_DOOR_79 jr z, .down cp COLL_STAIRCASE jr z, .down cp COLL_CAVE jr nz, .no_walk .down ld a, DOWN ld [WalkingDirection], a jr .continue_walk .no_walk xor a ret .continue_walk ld a, STEP_WALK call .DoStep ld a, 5 scf ret ; 80147 .CheckTurning: ; 80147 ; If the player is turning, change direction first. This also lets ; the player change facing without moving by tapping a direction. ld a, [wPlayerTurningDirection] cp 0 jr nz, .not_turning ld a, [WalkingDirection] cp STANDING jr z, .not_turning ld e, a ld a, [PlayerDirection] rrca rrca maskbits NUM_DIRECTIONS +- 1 cp e jr z, .not_turning ld a, STEP_TURN call .DoStep ld a, 2 scf ret .not_turning xor a ret ; 8016b .TryStep: ; 8016b ; Surfing actually calls .TrySurf directly instead of passing through here. ld a, [PlayerState] cp PLAYER_SURF jr z, .TrySurf cp PLAYER_SURF_PIKA jr z, .TrySurf call .CheckLandPerms jr c, .bump call .CheckNPC and a jr z, .bump cp 2 jr z, .bump ld a, [PlayerStandingTile] call CheckIceTile jr nc, .ice ; Downhill riding is slower when not moving down. call .BikeCheck jr nz, .walk ld hl, wBikeFlags bit 2, [hl] ; downhill jr z, .fast ld a, [WalkingDirection] cp DOWN jr z, .fast ld a, STEP_WALK call .DoStep scf ret .fast ld a, STEP_BIKE call .DoStep scf ret .walk ld a, STEP_WALK call .DoStep scf ret .ice ld a, STEP_ICE call .DoStep scf ret ; unused xor a ret .bump xor a ret ; 801c0 .TrySurf: ; 801c0 call .CheckSurfPerms ld [wd040], a jr c, .surf_bump call .CheckNPC ld [wd03f], a and a jr z, .surf_bump cp 2 jr z, .surf_bump ld a, [wd040] and a jr nz, .ExitWater ld a, STEP_WALK call .DoStep scf ret .ExitWater: call .GetOutOfWater call PlayMapMusic ld a, STEP_WALK call .DoStep ld a, 6 scf ret .surf_bump xor a ret ; 801f3 .TryJump: ; 801f3 ld a, [PlayerStandingTile] ld e, a and $f0 cp HI_NYBBLE_LEDGES jr nz, .DontJump ld a, e and 7 ld e, a ld d, 0 ld hl, .data_8021e add hl, de ld a, [FacingDirection] and [hl] jr z, .DontJump ld de, SFX_JUMP_OVER_LEDGE call PlaySFX ld a, STEP_LEDGE call .DoStep ld a, 7 scf ret .DontJump: xor a ret .data_8021e db FACE_RIGHT ; COLL_HOP_RIGHT db FACE_LEFT ; COLL_HOP_LEFT db FACE_UP ; COLL_HOP_UP db FACE_DOWN ; COLL_HOP_DOWN db FACE_RIGHT | FACE_DOWN ; COLL_HOP_DOWN_RIGHT db FACE_DOWN | FACE_LEFT ; COLL_HOP_DOWN_LEFT db FACE_UP | FACE_RIGHT ; COLL_HOP_UP_RIGHT db FACE_UP | FACE_LEFT ; COLL_HOP_UP_LEFT ; 80226 .CheckWarp: ; 80226 ; Bug: Since no case is made for STANDING here, it will check ; [.edgewarps + $ff]. This resolves to $3e at $8035a. ; This causes wd041 to be nonzero when standing on tile $3e, ; making bumps silent. ld a, [WalkingDirection] ; cp STANDING ; jr z, .not_warp ld e, a ld d, 0 ld hl, .EdgeWarps add hl, de ld a, [PlayerStandingTile] cp [hl] jr nz, .not_warp ld a, 1 ld [wd041], a ld a, [WalkingDirection] ; This is in the wrong place. cp STANDING jr z, .not_warp ld e, a ld a, [PlayerDirection] rrca rrca maskbits NUM_DIRECTIONS +- 1 cp e jr nz, .not_warp call WarpCheck jr nc, .not_warp call .StandInPlace scf ld a, 1 ret .not_warp xor a ret .EdgeWarps: db COLL_WARP_CARPET_DOWN db COLL_WARP_CARPET_UP db COLL_WARP_CARPET_LEFT db COLL_WARP_CARPET_RIGHT ; 8025f .DoStep: ld e, a ld d, 0 ld hl, .Steps add hl, de add hl, de ld a, [hli] ld h, [hl] ld l, a ld a, [WalkingDirection] ld e, a cp STANDING jp z, .StandInPlace add hl, de ld a, [hl] ld [MovementAnimation], a ld hl, .FinishFacing add hl, de ld a, [hl] ld [wPlayerTurningDirection], a ld a, 4 ret .Steps: dw .SlowStep dw .NormalStep dw .FastStep dw .JumpStep dw .SlideStep dw .TurningStep dw .BackJumpStep dw .FinishFacing .SlowStep: slow_step DOWN slow_step UP slow_step LEFT slow_step RIGHT .NormalStep: step DOWN step UP step LEFT step RIGHT .FastStep: big_step DOWN big_step UP big_step LEFT big_step RIGHT .JumpStep: jump_step DOWN jump_step UP jump_step LEFT jump_step RIGHT .SlideStep: fast_slide_step DOWN fast_slide_step UP fast_slide_step LEFT fast_slide_step RIGHT .BackJumpStep: jump_step UP jump_step DOWN jump_step RIGHT jump_step LEFT .TurningStep: turn_step DOWN turn_step UP turn_step LEFT turn_step RIGHT .FinishFacing: db $80 + DOWN db $80 + UP db $80 + LEFT db $80 + RIGHT ; 802b3 .StandInPlace: ; 802b3 ld a, 0 ld [wPlayerTurningDirection], a ld a, movement_step_sleep ld [MovementAnimation], a xor a ret ; 802bf ._WalkInPlace: ; 802bf ld a, 0 ld [wPlayerTurningDirection], a ld a, movement_step_bump ld [MovementAnimation], a xor a ret ; 802cb .CheckForced: ; 802cb ; When sliding on ice, input is forced to remain in the same direction. call CheckStandingOnIce ret nc ld a, [wPlayerTurningDirection] cp 0 ret z maskbits NUM_DIRECTIONS +- 1 ld e, a ld d, 0 ld hl, .forced_dpad add hl, de ld a, [CurInput] and BUTTONS or [hl] ld [CurInput], a ret .forced_dpad db D_DOWN, D_UP, D_LEFT, D_RIGHT ; 802ec .GetAction: ; 802ec ; Poll player input and update movement info. ld hl, .table ld de, .table2 - .table1 ld a, [CurInput] bit D_DOWN_F, a jr nz, .d_down bit D_UP_F, a jr nz, .d_up bit D_LEFT_F, a jr nz, .d_left bit D_RIGHT_F, a jr nz, .d_right ; Standing jr .update .d_down add hl, de .d_up add hl, de .d_left add hl, de .d_right add hl, de .update ld a, [hli] ld [WalkingDirection], a ld a, [hli] ld [FacingDirection], a ld a, [hli] ld [WalkingX], a ld a, [hli] ld [WalkingY], a ld a, [hli] ld h, [hl] ld l, a ld a, [hl] ld [WalkingTile], a ret .table ; struct: ; walk direction ; facing ; x movement ; y movement ; tile collision pointer .table1 db STANDING, FACE_CURRENT, 0, 0 dw PlayerStandingTile .table2 db RIGHT, FACE_RIGHT, 1, 0 dw TileRight db LEFT, FACE_LEFT, -1, 0 dw TileLeft db UP, FACE_UP, 0, -1 dw TileUp db DOWN, FACE_DOWN, 0, 1 dw TileDown ; 80341 .CheckNPC: ; 80341 ; Returns 0 if there is an NPC in front that you can't move ; Returns 1 if there is no NPC in front ; Returns 2 if there is a movable NPC in front ld a, 0 ld [hMapObjectIndexBuffer], a ; Load the next X coordinate into d ld a, [PlayerStandingMapX] ld d, a ld a, [WalkingX] add d ld d, a ; Load the next Y coordinate into e ld a, [PlayerStandingMapY] ld e, a ld a, [WalkingY] add e ld e, a ; Find an object struct with coordinates equal to d,e ld bc, ObjectStructs ; redundant farcall IsNPCAtCoord jr nc, .is_npc call .CheckStrengthBoulder jr c, .no_bump xor a ret .is_npc ld a, 1 ret .no_bump ld a, 2 ret ; 8036f .CheckStrengthBoulder: ; 8036f ld hl, wBikeFlags bit 0, [hl] ; using strength jr z, .not_boulder ld hl, OBJECT_DIRECTION_WALKING add hl, bc ld a, [hl] cp STANDING jr nz, .not_boulder ld hl, OBJECT_PALETTE add hl, bc bit 6, [hl] jr z, .not_boulder ld hl, OBJECT_FLAGS2 add hl, bc set 2, [hl] ld a, [WalkingDirection] ld d, a ld hl, OBJECT_RANGE add hl, bc ld a, [hl] and $fc or d ld [hl], a scf ret .not_boulder xor a ret ; 8039e .CheckLandPerms: ; 8039e ; Return 0 if walking onto land and tile permissions allow it. ; Otherwise, return carry. ld a, [TilePermissions] ld d, a ld a, [FacingDirection] and d jr nz, .NotWalkable ld a, [WalkingTile] call .CheckWalkable jr c, .NotWalkable xor a ret .NotWalkable: scf ret ; 803b4 .CheckSurfPerms: ; 803b4 ; Return 0 if moving in water, or 1 if moving onto land. ; Otherwise, return carry. ld a, [TilePermissions] ld d, a ld a, [FacingDirection] and d jr nz, .NotSurfable ld a, [WalkingTile] call .CheckSurfable jr c, .NotSurfable and a ret .NotSurfable: scf ret ; 803ca .BikeCheck: ; 803ca ld a, [PlayerState] cp PLAYER_BIKE ret z cp PLAYER_SKATE ret ; 803d3 .CheckWalkable: ; 803d3 ; Return 0 if tile a is land. Otherwise, return carry. call GetTileCollision and a ; LANDTILE? ret z scf ret ; 803da .CheckSurfable: ; 803da ; Return 0 if tile a is water, or 1 if land. ; Otherwise, return carry. call GetTileCollision cp WATERTILE jr z, .Water ; Can walk back onto land from water. and a ; LANDTILE? jr z, .Land jr .Neither .Water: xor a ret .Land: ld a, 1 and a ret .Neither: scf ret ; 803ee .BumpSound: ; 803ee call CheckSFX ret c ld de, SFX_BUMP call PlaySFX ret ; 803f9 .GetOutOfWater: ; 803f9 push bc ld a, PLAYER_NORMAL ld [PlayerState], a call ReplaceKrisSprite ; UpdateSprites pop bc ret ; 80404 CheckStandingOnIce:: ; 80404 ld a, [wPlayerTurningDirection] cp 0 jr z, .not_ice cp $f0 jr z, .not_ice ld a, [PlayerStandingTile] call CheckIceTile jr nc, .yep ld a, [PlayerState] cp PLAYER_SKATE jr nz, .not_ice .yep scf ret .not_ice and a ret ; 80422 StopPlayerForEvent:: ; 80422 ld hl, wPlayerNextMovement ld a, movement_step_sleep cp [hl] ret z ld [hl], a ld a, 0 ld [wPlayerTurningDirection], a ret ; 80430