406 lines
12 KiB
C
406 lines
12 KiB
C
#include "global.h"
|
|
#include "gflib.h"
|
|
#include "bike.h"
|
|
#include "event_object_movement.h"
|
|
#include "field_player_avatar.h"
|
|
#include "metatile_behavior.h"
|
|
#include "constants/event_object_movement.h"
|
|
#include "constants/songs.h"
|
|
|
|
EWRAM_DATA struct ObjectEvent * gUnknown_2036E30 = NULL;
|
|
EWRAM_DATA bool8 gUnknown_2036E34 = FALSE;
|
|
EWRAM_DATA struct ObjectEvent gObjectEvents[OBJECT_EVENTS_COUNT] = {};
|
|
EWRAM_DATA struct PlayerAvatar gPlayerAvatar = {};
|
|
|
|
u8 ObjectEventCB2_NoMovement2(struct ObjectEvent * object, struct Sprite * sprite);
|
|
bool8 sub_805B528(void);
|
|
bool8 TryInterruptObjectEventSpecialAnim(struct ObjectEvent * playerObjEvent, u8 direction);
|
|
void npc_clear_strange_bits(struct ObjectEvent * playerObjEvent);
|
|
void DoPlayerAvatarTransition(void);
|
|
bool8 TryDoMetatileBehaviorForcedMovement(void);
|
|
void MovePlayerAvatarUsingKeypadInput(u8 direction, u16 newKeys, u16 heldKeys);
|
|
void PlayerAllowForcedMovementIfMovingSameDirection(void);
|
|
bool8 ForcedMovement_None(void);
|
|
void PlayerJumpLedge(u8 direction);
|
|
u8 CheckForPlayerAvatarCollision(u8 direction);
|
|
bool8 ForcedMovement_Slip(void);
|
|
bool8 ForcedMovement_WalkSouth(void);
|
|
bool8 ForcedMovement_WalkNorth(void);
|
|
bool8 ForcedMovement_WalkWest(void);
|
|
bool8 ForcedMovement_WalkEast(void);
|
|
bool8 ForcedMovement_SpinRight(void);
|
|
bool8 ForcedMovement_SpinLeft(void);
|
|
bool8 ForcedMovement_SpinUp(void);
|
|
bool8 ForcedMovement_SpinDown(void);
|
|
void PlaySpinSound(void);
|
|
bool8 ForcedMovement_PushedSouthByCurrent(void);
|
|
bool8 ForcedMovement_PushedNorthByCurrent(void);
|
|
bool8 ForcedMovement_PushedWestByCurrent(void);
|
|
bool8 ForcedMovement_PushedEastByCurrent(void);
|
|
bool8 ForcedMovement_SlideSouth(void);
|
|
bool8 ForcedMovement_SlideNorth(void);
|
|
bool8 ForcedMovement_SlideWest(void);
|
|
bool8 ForcedMovement_SlideEast(void);
|
|
bool8 ForcedMovement_0xBB(void);
|
|
bool8 ForcedMovement_0xBC(void);
|
|
u8 CheckMovementInputNotOnBike(u8 direction);
|
|
void PlayerNotOnBikeNotMoving(u8 direction, u16 heldKeys);
|
|
void PlayerNotOnBikeTurningInPlace(u8 direction, u16 heldKeys);
|
|
void PlayerNotOnBikeMoving(u8 direction, u16 heldKeys);
|
|
void PlayerGoSpeed2(u8 direction);
|
|
void PlayerGoSpeed1(u8 direction);
|
|
void PlayerGoSpin(u8 direction);
|
|
void PlayerRideWaterCurrent(u8 direction);
|
|
void sub_805C2CC(u8 metatileBehavior);
|
|
void sub_805CC40(struct ObjectEvent * playerObjEvent);
|
|
void DoPlayerMatJump(void);
|
|
void DoPlayerMatSpin(void);
|
|
|
|
void MovementType_Player(struct Sprite *sprite)
|
|
{
|
|
UpdateObjectEventCurrentMovement(&gObjectEvents[sprite->data[0]], sprite, ObjectEventCB2_NoMovement2);
|
|
}
|
|
|
|
u8 ObjectEventCB2_NoMovement2(struct ObjectEvent * object, struct Sprite * sprite)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void player_step(u8 direction, u16 newKeys, u16 heldKeys)
|
|
{
|
|
struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId];
|
|
|
|
sub_805CC40(playerObjEvent);
|
|
if (!gPlayerAvatar.preventStep && !sub_805B528())
|
|
{
|
|
if (!TryInterruptObjectEventSpecialAnim(playerObjEvent, direction))
|
|
{
|
|
npc_clear_strange_bits(playerObjEvent);
|
|
DoPlayerAvatarTransition();
|
|
if (!TryDoMetatileBehaviorForcedMovement())
|
|
{
|
|
MovePlayerAvatarUsingKeypadInput(direction, newKeys, heldKeys);
|
|
PlayerAllowForcedMovementIfMovingSameDirection();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool8 TryInterruptObjectEventSpecialAnim(struct ObjectEvent *playerObjEvent, u8 direction)
|
|
{
|
|
|
|
if (ObjectEventIsMovementOverridden(playerObjEvent)
|
|
&& !ObjectEventClearHeldMovementIfFinished(playerObjEvent))
|
|
{
|
|
u8 heldMovementActionId = ObjectEventGetHeldMovementActionId(playerObjEvent);
|
|
if (heldMovementActionId > MOVEMENT_ACTION_WALK_FAST_RIGHT && heldMovementActionId < MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_DOWN)
|
|
{
|
|
if (direction != DIR_NONE && playerObjEvent->movementDirection != direction)
|
|
{
|
|
ObjectEventClearHeldMovement(playerObjEvent);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void npc_clear_strange_bits(struct ObjectEvent *objEvent)
|
|
{
|
|
objEvent->inanimate = 0;
|
|
objEvent->disableAnim = 0;
|
|
objEvent->facingDirectionLocked = 0;
|
|
gPlayerAvatar.flags &= ~PLAYER_AVATAR_FLAG_DASH;
|
|
}
|
|
|
|
void MovePlayerAvatarUsingKeypadInput(u8 direction, u16 newKeys, u16 heldKeys)
|
|
{
|
|
if ((gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_MACH_BIKE)
|
|
|| (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_ACRO_BIKE))
|
|
MovePlayerOnBike(direction, newKeys, heldKeys);
|
|
else
|
|
MovePlayerNotOnBike(direction, heldKeys);
|
|
}
|
|
|
|
void PlayerAllowForcedMovementIfMovingSameDirection(void)
|
|
{
|
|
if (gPlayerAvatar.runningState == MOVING)
|
|
gPlayerAvatar.flags &= ~PLAYER_AVATAR_FLAG_FORCED_MVMT_DISABLED;
|
|
}
|
|
|
|
bool8 sub_805B528(void)
|
|
{
|
|
if ((gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_MVMT_IS_FORCED) && MetatileBehavior_IsSpinTile(gPlayerAvatar.unk1C))
|
|
{
|
|
gUnknown_2036E30 = &gObjectEvents[gPlayerAvatar.objectEventId];
|
|
if (gUnknown_2036E30->heldMovementFinished)
|
|
{
|
|
if (MetatileBehavior_IsStopSpinning(gUnknown_2036E30->currentMetatileBehavior))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (MetatileBehavior_IsSpinTile(gUnknown_2036E30->currentMetatileBehavior))
|
|
{
|
|
gPlayerAvatar.unk1C = gUnknown_2036E30->currentMetatileBehavior;
|
|
}
|
|
ObjectEventClearHeldMovement(gUnknown_2036E30);
|
|
sub_805C2CC(gPlayerAvatar.unk1C);
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
const struct {
|
|
bool8 (*unk0)(u8 metatileBehavior);
|
|
bool8 (*unk4)(void);
|
|
} sForcedMovementFuncs[] = {
|
|
{MetatileBehavior_IsUnknownMovement48, ForcedMovement_Slip},
|
|
{MetatileBehavior_IsIce_2, ForcedMovement_Slip},
|
|
{MetatileBehavior_IsWalkSouth, ForcedMovement_WalkSouth},
|
|
{MetatileBehavior_IsWalkNorth, ForcedMovement_WalkNorth},
|
|
{MetatileBehavior_IsWalkWest, ForcedMovement_WalkWest},
|
|
{MetatileBehavior_IsWalkEast, ForcedMovement_WalkEast},
|
|
{MetatileBehavior_IsSouthwardCurrent, ForcedMovement_PushedSouthByCurrent},
|
|
{MetatileBehavior_IsNorthwardCurrent, ForcedMovement_PushedNorthByCurrent},
|
|
{MetatileBehavior_IsWestwardCurrent, ForcedMovement_PushedWestByCurrent},
|
|
{MetatileBehavior_IsEastwardCurrent, ForcedMovement_PushedEastByCurrent},
|
|
{MetatileBehavior_IsSpinRight, ForcedMovement_SpinRight},
|
|
{MetatileBehavior_IsSpinLeft, ForcedMovement_SpinLeft},
|
|
{MetatileBehavior_IsSpinUp, ForcedMovement_SpinUp},
|
|
{MetatileBehavior_IsSpinDown, ForcedMovement_SpinDown},
|
|
{MetatileBehavior_IsSlideSouth, ForcedMovement_SlideSouth},
|
|
{MetatileBehavior_IsSlideNorth, ForcedMovement_SlideNorth},
|
|
{MetatileBehavior_IsSlideWest, ForcedMovement_SlideWest},
|
|
{MetatileBehavior_IsSlideEast, ForcedMovement_SlideEast},
|
|
{MetatileBehavior_IsWaterfall, ForcedMovement_PushedSouthByCurrent},
|
|
{MetatileBehavior_UnusedReturnFalse_7, ForcedMovement_0xBB},
|
|
{MetatileBehavior_UnusedReturnFalse_8, ForcedMovement_0xBC},
|
|
{NULL, ForcedMovement_None},
|
|
};
|
|
|
|
bool8 TryDoMetatileBehaviorForcedMovement(void)
|
|
{
|
|
int i;
|
|
u8 behavior;
|
|
if (!(gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_FORCED_MVMT_DISABLED))
|
|
{
|
|
behavior = gObjectEvents[gPlayerAvatar.objectEventId].currentMetatileBehavior;
|
|
for (i = 0; sForcedMovementFuncs[i].unk0 != NULL; i++)
|
|
{
|
|
if (sForcedMovementFuncs[i].unk0(behavior))
|
|
{
|
|
gPlayerAvatar.unk1C = behavior;
|
|
return sForcedMovementFuncs[i].unk4();
|
|
}
|
|
}
|
|
return sForcedMovementFuncs[i].unk4();
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; sForcedMovementFuncs[i].unk0 != NULL; i++)
|
|
;
|
|
return sForcedMovementFuncs[i].unk4();
|
|
}
|
|
}
|
|
|
|
bool8 ForcedMovement_None(void)
|
|
{
|
|
if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_MVMT_IS_FORCED)
|
|
{
|
|
struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId];
|
|
|
|
playerObjEvent->facingDirectionLocked = FALSE;
|
|
playerObjEvent->enableAnim = TRUE;
|
|
SetObjectEventDirection(playerObjEvent, playerObjEvent->facingDirection);
|
|
gPlayerAvatar.flags &= ~PLAYER_AVATAR_FLAG_MVMT_IS_FORCED;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
u8 DoForcedMovement(u8 direction, MovementAction movementAction)
|
|
{
|
|
struct PlayerAvatar *playerAvatar = &gPlayerAvatar;
|
|
u8 collision = CheckForPlayerAvatarCollision(direction);
|
|
|
|
playerAvatar->flags |= PLAYER_AVATAR_FLAG_MVMT_IS_FORCED;
|
|
if (collision)
|
|
{
|
|
ForcedMovement_None();
|
|
if (collision < COLLISION_STOP_SURFING)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if (collision == COLLISION_LEDGE_JUMP)
|
|
PlayerJumpLedge(direction);
|
|
playerAvatar->flags |= PLAYER_AVATAR_FLAG_MVMT_IS_FORCED;
|
|
playerAvatar->runningState = MOVING;
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
playerAvatar->runningState = MOVING;
|
|
movementAction(direction);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
u8 DoForcedMovementInCurrentDirection(MovementAction movementAction)
|
|
{
|
|
struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId];
|
|
|
|
playerObjEvent->disableAnim = TRUE;
|
|
return DoForcedMovement(playerObjEvent->movementDirection, movementAction);
|
|
}
|
|
|
|
bool8 ForcedMovement_Slip(void)
|
|
{
|
|
return DoForcedMovementInCurrentDirection(PlayerGoSpeed2);
|
|
}
|
|
|
|
bool8 ForcedMovement_WalkSouth(void)
|
|
{
|
|
return DoForcedMovement(DIR_SOUTH, PlayerGoSpeed1);
|
|
}
|
|
|
|
bool8 ForcedMovement_WalkNorth(void)
|
|
{
|
|
return DoForcedMovement(DIR_NORTH, PlayerGoSpeed1);
|
|
}
|
|
|
|
bool8 ForcedMovement_WalkWest(void)
|
|
{
|
|
return DoForcedMovement(DIR_WEST, PlayerGoSpeed1);
|
|
}
|
|
|
|
bool8 ForcedMovement_WalkEast(void)
|
|
{
|
|
return DoForcedMovement(DIR_EAST, PlayerGoSpeed1);
|
|
}
|
|
|
|
bool8 ForcedMovement_SpinRight(void)
|
|
{
|
|
PlaySpinSound();
|
|
return DoForcedMovement(DIR_EAST, PlayerGoSpin);
|
|
}
|
|
|
|
bool8 ForcedMovement_SpinLeft(void)
|
|
{
|
|
PlaySpinSound();
|
|
return DoForcedMovement(DIR_WEST, PlayerGoSpin);
|
|
}
|
|
|
|
bool8 ForcedMovement_SpinUp(void)
|
|
{
|
|
PlaySpinSound();
|
|
return DoForcedMovement(DIR_NORTH, PlayerGoSpin);
|
|
}
|
|
|
|
bool8 ForcedMovement_SpinDown(void)
|
|
{
|
|
PlaySpinSound();
|
|
return DoForcedMovement(DIR_SOUTH, PlayerGoSpin);
|
|
}
|
|
|
|
void PlaySpinSound(void)
|
|
{
|
|
PlaySE(SE_W013B);
|
|
}
|
|
|
|
bool8 ForcedMovement_PushedSouthByCurrent(void)
|
|
{
|
|
return DoForcedMovement(DIR_SOUTH, PlayerRideWaterCurrent);
|
|
}
|
|
|
|
bool8 ForcedMovement_PushedNorthByCurrent(void)
|
|
{
|
|
return DoForcedMovement(DIR_NORTH, PlayerRideWaterCurrent);
|
|
}
|
|
|
|
bool8 ForcedMovement_PushedWestByCurrent(void)
|
|
{
|
|
return DoForcedMovement(DIR_WEST, PlayerRideWaterCurrent);
|
|
}
|
|
|
|
bool8 ForcedMovement_PushedEastByCurrent(void)
|
|
{
|
|
return DoForcedMovement(DIR_EAST, PlayerRideWaterCurrent);
|
|
}
|
|
|
|
u8 ForcedMovement_Slide(u8 direction, MovementAction movementAction)
|
|
{
|
|
struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId];
|
|
|
|
playerObjEvent->disableAnim = TRUE;
|
|
playerObjEvent->facingDirectionLocked = TRUE;
|
|
return DoForcedMovement(direction, movementAction);
|
|
}
|
|
|
|
bool8 ForcedMovement_SlideSouth(void)
|
|
{
|
|
return ForcedMovement_Slide(DIR_SOUTH, PlayerGoSpeed2);
|
|
}
|
|
|
|
bool8 ForcedMovement_SlideNorth(void)
|
|
{
|
|
return ForcedMovement_Slide(DIR_NORTH, PlayerGoSpeed2);
|
|
}
|
|
|
|
bool8 ForcedMovement_SlideWest(void)
|
|
{
|
|
return ForcedMovement_Slide(DIR_WEST, PlayerGoSpeed2);
|
|
}
|
|
|
|
bool8 ForcedMovement_SlideEast(void)
|
|
{
|
|
return ForcedMovement_Slide(DIR_EAST, PlayerGoSpeed2);
|
|
}
|
|
|
|
bool8 ForcedMovement_0xBB(void)
|
|
{
|
|
DoPlayerMatJump();
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 ForcedMovement_0xBC(void)
|
|
{
|
|
DoPlayerMatSpin();
|
|
return TRUE;
|
|
}
|
|
|
|
void (*const gUnknown_835B814[])(u8, u16) = {
|
|
PlayerNotOnBikeNotMoving,
|
|
PlayerNotOnBikeTurningInPlace,
|
|
PlayerNotOnBikeMoving
|
|
};
|
|
|
|
void MovePlayerNotOnBike(u8 direction, u16 heldKeys)
|
|
{
|
|
gUnknown_835B814[CheckMovementInputNotOnBike(direction)](direction, heldKeys);
|
|
}
|
|
|
|
u8 CheckMovementInputNotOnBike(u8 direction)
|
|
{
|
|
if (direction == DIR_NONE)
|
|
{
|
|
gPlayerAvatar.runningState = NOT_MOVING;
|
|
return 0;
|
|
}
|
|
else if (direction != GetPlayerMovementDirection() && gPlayerAvatar.runningState != MOVING)
|
|
{
|
|
gPlayerAvatar.runningState = TURN_DIRECTION;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
gPlayerAvatar.runningState = MOVING;
|
|
return 2;
|
|
}
|
|
}
|