diff --git a/data/layouts/PetalburgCity/map.bin b/data/layouts/PetalburgCity/map.bin index 35f0172ca2..46c808e055 100644 Binary files a/data/layouts/PetalburgCity/map.bin and b/data/layouts/PetalburgCity/map.bin differ diff --git a/include/config/overworld.h b/include/config/overworld.h index 77ad62f652..fc6865f53f 100644 --- a/include/config/overworld.h +++ b/include/config/overworld.h @@ -3,6 +3,7 @@ // Movement config #define OW_RUNNING_INDOORS GEN_LATEST // In Gen4+, players are allowed to run indoors. +#define SLOW_MOVEMENT_ON_STAIRS TRUE // If enabled, the player will move slower up/down stairs like in FR // Other settings #define OW_POISON_DAMAGE GEN_LATEST // In Gen4, Pokémon no longer faint from Poison in the overworld. In Gen5+, they no longer take damage at all. diff --git a/include/constants/event_object_movement.h b/include/constants/event_object_movement.h index e7641f9826..650a6a2357 100755 --- a/include/constants/event_object_movement.h +++ b/include/constants/event_object_movement.h @@ -247,6 +247,10 @@ #define MOVEMENT_ACTION_EMOTE_DOUBLE_EXCL_MARK 0x9F #define MOVEMENT_ACTION_EXIT_POKEBALL 0xA0 #define MOVEMENT_ACTION_ENTER_POKEBALL 0xA1 +#define MOVEMENT_ACTION_RUN_DOWN_SLOW 0xA2 // slow running for rocky stairs +#define MOVEMENT_ACTION_RUN_UP_SLOW 0xA3 +#define MOVEMENT_ACTION_RUN_LEFT_SLOW 0xA4 +#define MOVEMENT_ACTION_RUN_RIGHT_SLOW 0xA5 #define MOVEMENT_ACTION_STEP_END 0xFE #define MOVEMENT_ACTION_NONE 0xFF diff --git a/include/constants/metatile_behaviors.h b/include/constants/metatile_behaviors.h index 1f6d4e87cb..40ee0aab1a 100755 --- a/include/constants/metatile_behaviors.h +++ b/include/constants/metatile_behaviors.h @@ -74,13 +74,13 @@ #define MB_SLIDE_NORTH 0x46 #define MB_SLIDE_SOUTH 0x47 #define MB_TRICK_HOUSE_PUZZLE_8_FLOOR 0x48 -#define MB_UNUSED_49 0x49 -#define MB_UNUSED_4A 0x4A -#define MB_UNUSED_4B 0x4B -#define MB_UNUSED_4C 0x4C -#define MB_UNUSED_4D 0x4D -#define MB_UNUSED_4E 0x4E -#define MB_UNUSED_4F 0x4F +#define MB_SIDEWAYS_STAIRS_RIGHT_SIDE 0x49 +#define MB_SIDEWAYS_STAIRS_LEFT_SIDE 0x4A +#define MB_SIDEWAYS_STAIRS_RIGHT_SIDE_TOP 0x4B +#define MB_SIDEWAYS_STAIRS_LEFT_SIDE_TOP 0x4C +#define MB_SIDEWAYS_STAIRS_RIGHT_SIDE_BOTTOM 0x4D +#define MB_SIDEWAYS_STAIRS_LEFT_SIDE_BOTTOM 0x4E +#define MB_ROCK_STAIRS 0x4F #define MB_EASTWARD_CURRENT 0x50 #define MB_WESTWARD_CURRENT 0x51 #define MB_NORTHWARD_CURRENT 0x52 diff --git a/include/event_object_movement.h b/include/event_object_movement.h index 2906789b37..ff90b8a1c0 100644 --- a/include/event_object_movement.h +++ b/include/event_object_movement.h @@ -484,6 +484,15 @@ void SetVirtualObjectInvisibility(u8 virtualObjId, bool32 invisible); bool32 IsVirtualObjectInvisible(u8 virtualObjId); void SetVirtualObjectSpriteAnim(u8 virtualObjId, u8 animNum); bool32 IsVirtualObjectAnimating(u8 virtualObjId); +u8 GetObjectEventIdByLocalId(u8 localId); +bool32 IsFollowerVisible(void); + +// run slow +u8 GetPlayerRunSlowMovementAction(u32); +//sideways stairs +u8 GetSidewaysStairsToRightDirection(s16, s16, u8); +u8 GetSidewaysStairsToLeftDirection(s16, s16, u8); +u8 GetSidewaysStairsCollision(struct ObjectEvent *objectEvent, u8 dir, u8 currentBehavior, u8 nextBehavior, u8 collision); bool8 MovementAction_EmoteX_Step0(struct ObjectEvent *, struct Sprite *); bool8 MovementAction_EmoteDoubleExclamationMark_Step0(struct ObjectEvent *, struct Sprite *); diff --git a/include/field_player_avatar.h b/include/field_player_avatar.h index caf28afb87..12de71be8f 100644 --- a/include/field_player_avatar.h +++ b/include/field_player_avatar.h @@ -64,5 +64,9 @@ bool32 IsPlayerSpinExitActive(void); void SetPlayerInvisibility(bool8 invisible); u8 player_get_pos_including_state_based_drift(s16 *x, s16 *y); void StartFishing(u8 rod); +bool8 ObjectMovingOnRockStairs(struct ObjectEvent *objectEvent, u8 direction); +//sideways stairs +u8 GetRightSideStairsDirection(u8 direction); +u8 GetLeftSideStairsDirection(u8 direction); #endif // GUARD_FIELD_PLAYER_AVATAR_H diff --git a/include/global.fieldmap.h b/include/global.fieldmap.h index c606eef8d3..4cbb23d499 100644 --- a/include/global.fieldmap.h +++ b/include/global.fieldmap.h @@ -217,7 +217,8 @@ struct ObjectEvent /*0x1D*/ u8 trainerRange_berryTreeId; /*0x1E*/ u8 currentMetatileBehavior; /*0x1F*/ u8 previousMetatileBehavior; - /*0x20*/ u8 previousMovementDirection; + /*0x20*/ u8 previousMovementDirection:4; + u8 directionOverwrite:4; /*0x21*/ u8 directionSequenceIndex; /*0x22*/ u8 playerCopyableMovement; // COPY_MOVE_* /*0x23*/ u8 spriteId; @@ -297,6 +298,9 @@ enum COLLISION_ISOLATED_HORIZONTAL_RAIL, COLLISION_VERTICAL_RAIL, COLLISION_HORIZONTAL_RAIL, + //sideways_stairs + COLLISION_SIDEWAYS_STAIRS_TO_RIGHT, + COLLISION_SIDEWAYS_STAIRS_TO_LEFT }; // player running states diff --git a/include/metatile_behavior.h b/include/metatile_behavior.h index c2d0d23ee3..da7946e62e 100644 --- a/include/metatile_behavior.h +++ b/include/metatile_behavior.h @@ -148,5 +148,15 @@ bool8 MetatileBehavior_IsQuestionnaire(u8); bool8 MetatileBehavior_IsLongGrass_Duplicate(u8); bool8 MetatileBehavior_IsLongGrassSouthEdge(u8); bool8 MetatileBehavior_IsTrainerHillTimer(u8); +bool8 MetatileBehavior_IsRockStairs(u8); +//sideways stairs +bool8 MetatileBehavior_IsSidewaysStairsRightSide(u8); +bool8 MetatileBehavior_IsSidewaysStairsLeftSide(u8); +bool8 MetatileBehavior_IsSidewaysStairsRightSideTop(u8 metatileBehavior); +bool8 MetatileBehavior_IsSidewaysStairsLeftSideTop(u8 metatileBehavior); +bool8 MetatileBehavior_IsSidewaysStairsRightSideBottom(u8 metatileBehavior); +bool8 MetatileBehavior_IsSidewaysStairsLeftSideBottom(u8 metatileBehavior); +bool8 MetatileBehavior_IsSidewaysStairsRightSideAny(u8 metatileBehavior); +bool8 MetatileBehavior_IsSidewaysStairsLeftSideAny(u8 metatileBehavior); #endif // GUARD_METATILE_BEHAVIOR_H diff --git a/src/bike.c b/src/bike.c index de150dae4b..1cfecfe152 100644 --- a/src/bike.c +++ b/src/bike.c @@ -142,6 +142,19 @@ static u8 GetMachBikeTransition(u8 *dirTraveling) { // if the dir updated before this function, get the relevent new direction to check later. u8 direction = GetPlayerMovementDirection(); + + // fix direction when moving on sideways stairs + switch (direction) + { + case DIR_SOUTHWEST: + case DIR_NORTHWEST: + direction = DIR_WEST; + break; + case DIR_SOUTHEAST: + case DIR_NORTHEAST: + direction = DIR_EAST; + break; + } // is the player standing still? if (*dirTraveling == 0) @@ -193,7 +206,7 @@ static void MachBikeTransition_TurnDirection(u8 direction) Bike_SetBikeStill(); } else - { + { MachBikeTransition_FaceDirection(playerObjEvent->facingDirection); } } @@ -233,7 +246,9 @@ static void MachBikeTransition_TrySpeedUp(u8 direction) } else { - // we did not hit anything that can slow us down, so perform the advancement callback depending on the bikeFrameCounter and try to increase the mach bike's speed. + if (ObjectMovingOnRockStairs(playerObjEvent, direction) && gPlayerAvatar.bikeFrameCounter > 1) + gPlayerAvatar.bikeFrameCounter--; + sMachBikeSpeedCallbacks[gPlayerAvatar.bikeFrameCounter](direction); gPlayerAvatar.bikeSpeed = gPlayerAvatar.bikeFrameCounter + (gPlayerAvatar.bikeFrameCounter >> 1); // same as dividing by 2, but compiler is insistent on >> 1 if (gPlayerAvatar.bikeFrameCounter < 2) // do not go faster than the last element in the mach bike array @@ -368,6 +383,7 @@ static u8 AcroBikeHandleInputWheelieStanding(u8 *newDirection, u16 newKeys, u16 struct ObjectEvent *playerObjEvent; direction = GetPlayerMovementDirection(); + playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; gPlayerAvatar.runningState = NOT_MOVING; @@ -563,7 +579,10 @@ static void AcroBikeTransition_Moving(u8 direction) } else { - PlayerRideWaterCurrent(direction); + if (ObjectMovingOnRockStairs(playerObjEvent, direction)) + PlayerWalkFast(direction); + else + PlayerRideWaterCurrent(direction); } } @@ -696,6 +715,7 @@ static void AcroBikeTransition_WheelieMoving(u8 direction) } return; } + PlayerWheelieMove(direction); gPlayerAvatar.runningState = MOVING; } @@ -730,6 +750,7 @@ static void AcroBikeTransition_WheelieRisingMoving(u8 direction) } return; } + PlayerPopWheelieWhileMoving(direction); gPlayerAvatar.runningState = MOVING; } @@ -753,6 +774,7 @@ static void AcroBikeTransition_WheelieLoweringMoving(u8 direction) PlayerEndWheelie(direction); return; } + PlayerEndWheelieWhileMoving(direction); } diff --git a/src/data/object_events/movement_action_func_tables.h b/src/data/object_events/movement_action_func_tables.h index a605b3f0b2..0ee3e78afc 100755 --- a/src/data/object_events/movement_action_func_tables.h +++ b/src/data/object_events/movement_action_func_tables.h @@ -266,6 +266,12 @@ u8 MovementAction_FlyUp_Step1(struct ObjectEvent *, struct Sprite *); u8 MovementAction_Fly_Finish(struct ObjectEvent *, struct Sprite *); u8 MovementAction_FlyDown_Step0(struct ObjectEvent *, struct Sprite *); u8 MovementAction_FlyDown_Step1(struct ObjectEvent *, struct Sprite *); +//slow running +u8 MovementActionFunc_RunSlowDown_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite); +u8 MovementActionFunc_RunSlowUp_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite); +u8 MovementActionFunc_RunSlowLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite); +u8 MovementActionFunc_RunSlowRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite); +u8 MovementActionFunc_RunSlow_Step1(struct ObjectEvent *objectEvent, struct Sprite *sprite); u8 (*const gMovementActionFuncs_FaceDown[])(struct ObjectEvent *, struct Sprite *); u8 (*const gMovementActionFuncs_FaceUp[])(struct ObjectEvent *, struct Sprite *); @@ -429,6 +435,11 @@ u8 (*const gMovementActionFuncs_FlyUp[])(struct ObjectEvent *, struct Sprite *); u8 (*const gMovementActionFuncs_FlyDown[])(struct ObjectEvent *, struct Sprite *); u8 (*const gMovementActionFuncs_EmoteX[])(struct ObjectEvent *, struct Sprite *); u8 (*const gMovementActionFuncs_EmoteDoubleExclMark[])(struct ObjectEvent *, struct Sprite *); +//run slow +u8 (*const gMovementActionFuncs_RunDownSlow[])(struct ObjectEvent *, struct Sprite *); +u8 (*const gMovementActionFuncs_RunUpSlow[])(struct ObjectEvent *, struct Sprite *); +u8 (*const gMovementActionFuncs_RunLeftSlow[])(struct ObjectEvent *, struct Sprite *); +u8 (*const gMovementActionFuncs_RunRightSlow[])(struct ObjectEvent *, struct Sprite *); u8 (*const *const gMovementActionFuncs[])(struct ObjectEvent *, struct Sprite *) = { [MOVEMENT_ACTION_FACE_DOWN] = gMovementActionFuncs_FaceDown, @@ -593,6 +604,11 @@ u8 (*const *const gMovementActionFuncs[])(struct ObjectEvent *, struct Sprite *) [MOVEMENT_ACTION_EMOTE_DOUBLE_EXCL_MARK] = gMovementActionFuncs_EmoteDoubleExclMark, [MOVEMENT_ACTION_EXIT_POKEBALL] = gMovementActionFuncs_ExitPokeball, [MOVEMENT_ACTION_ENTER_POKEBALL] = gMovementActionFuncs_EnterPokeball, + //run slow + [MOVEMENT_ACTION_RUN_DOWN_SLOW] = gMovementActionFuncs_RunDownSlow, + [MOVEMENT_ACTION_RUN_UP_SLOW] = gMovementActionFuncs_RunUpSlow, + [MOVEMENT_ACTION_RUN_LEFT_SLOW] = gMovementActionFuncs_RunLeftSlow, + [MOVEMENT_ACTION_RUN_RIGHT_SLOW] = gMovementActionFuncs_RunRightSlow, }; u8 (*const gMovementActionFuncs_FaceDown[])(struct ObjectEvent *, struct Sprite *) = { @@ -1554,3 +1570,28 @@ u8 (*const gMovementActionFuncs_EmoteDoubleExclMark[])(struct ObjectEvent *, str MovementAction_EmoteDoubleExclamationMark_Step0, MovementAction_Finish, }; + +//slow running +u8 (*const gMovementActionFuncs_RunDownSlow[])(struct ObjectEvent *, struct Sprite *) = { + MovementActionFunc_RunSlowDown_Step0, + MovementActionFunc_RunSlow_Step1, + MovementAction_PauseSpriteAnim, +}; + +u8 (*const gMovementActionFuncs_RunUpSlow[])(struct ObjectEvent *, struct Sprite *) = { + MovementActionFunc_RunSlowUp_Step0, + MovementActionFunc_RunSlow_Step1, + MovementAction_PauseSpriteAnim, +}; + +u8 (*const gMovementActionFuncs_RunLeftSlow[])(struct ObjectEvent *, struct Sprite *) = { + MovementActionFunc_RunSlowLeft_Step0, + MovementActionFunc_RunSlow_Step1, + MovementAction_PauseSpriteAnim, +}; + +u8 (*const gMovementActionFuncs_RunRightSlow[])(struct ObjectEvent *, struct Sprite *) = { + MovementActionFunc_RunSlowRight_Step0, + MovementActionFunc_RunSlow_Step1, + MovementAction_PauseSpriteAnim, +}; diff --git a/src/event_object_movement.c b/src/event_object_movement.c index 80a36d6818..df5c4fd14b 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -49,6 +49,7 @@ #include "constants/region_map_sections.h" #include "constants/songs.h" #include "constants/species.h" +#include "constants/metatile_behaviors.h" #include "constants/trainer_types.h" #include "constants/union_room.h" #include "constants/weather.h" @@ -157,7 +158,6 @@ static void ApplyLevitateMovement(u8); static bool8 MovementType_Disguise_Callback(struct ObjectEvent *, struct Sprite *); static bool8 MovementType_Buried_Callback(struct ObjectEvent *, struct Sprite *); static void CreateReflectionEffectSprites(void); -static u8 GetObjectEventIdByLocalId(u8); static u8 GetObjectEventIdByLocalIdAndMapInternal(u8, u8, u8); static bool8 GetAvailableObjectEventId(u16, u8, u8, u8 *); static void SetObjectEventDynamicGraphicsId(struct ObjectEvent *); @@ -207,6 +207,8 @@ static void CopyObjectGraphicsInfoToSpriteTemplate_WithMovementType(u16 graphics static const struct SpriteFrameImage sPicTable_PechaBerryTree[]; +static void StartSlowRunningAnim(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8 direction); + const u8 gReflectionEffectPaletteMap[16] = { [PALSLOT_PLAYER] = PALSLOT_PLAYER_REFLECTION, [PALSLOT_PLAYER_REFLECTION] = PALSLOT_PLAYER_REFLECTION, @@ -744,10 +746,10 @@ static const u8 sFaceDirectionAnimNums[] = { [DIR_NORTH] = ANIM_STD_FACE_NORTH, [DIR_WEST] = ANIM_STD_FACE_WEST, [DIR_EAST] = ANIM_STD_FACE_EAST, - [DIR_SOUTHWEST] = ANIM_STD_FACE_SOUTH, - [DIR_SOUTHEAST] = ANIM_STD_FACE_SOUTH, - [DIR_NORTHWEST] = ANIM_STD_FACE_NORTH, - [DIR_NORTHEAST] = ANIM_STD_FACE_NORTH, + [DIR_SOUTHWEST] = ANIM_STD_FACE_WEST, + [DIR_SOUTHEAST] = ANIM_STD_FACE_EAST, + [DIR_NORTHWEST] = ANIM_STD_FACE_WEST, + [DIR_NORTHEAST] = ANIM_STD_FACE_EAST, }; static const u8 sMoveDirectionAnimNums[] = { [DIR_NONE] = ANIM_STD_GO_SOUTH, @@ -755,10 +757,10 @@ static const u8 sMoveDirectionAnimNums[] = { [DIR_NORTH] = ANIM_STD_GO_NORTH, [DIR_WEST] = ANIM_STD_GO_WEST, [DIR_EAST] = ANIM_STD_GO_EAST, - [DIR_SOUTHWEST] = ANIM_STD_GO_SOUTH, - [DIR_SOUTHEAST] = ANIM_STD_GO_SOUTH, - [DIR_NORTHWEST] = ANIM_STD_GO_NORTH, - [DIR_NORTHEAST] = ANIM_STD_GO_NORTH, + [DIR_SOUTHWEST] = ANIM_STD_GO_WEST, + [DIR_SOUTHEAST] = ANIM_STD_GO_EAST, + [DIR_NORTHWEST] = ANIM_STD_GO_WEST, + [DIR_NORTHEAST] = ANIM_STD_GO_EAST, }; static const u8 sMoveDirectionFastAnimNums[] = { [DIR_NONE] = ANIM_STD_GO_FAST_SOUTH, @@ -766,10 +768,10 @@ static const u8 sMoveDirectionFastAnimNums[] = { [DIR_NORTH] = ANIM_STD_GO_FAST_NORTH, [DIR_WEST] = ANIM_STD_GO_FAST_WEST, [DIR_EAST] = ANIM_STD_GO_FAST_EAST, - [DIR_SOUTHWEST] = ANIM_STD_GO_FAST_SOUTH, - [DIR_SOUTHEAST] = ANIM_STD_GO_FAST_SOUTH, - [DIR_NORTHWEST] = ANIM_STD_GO_FAST_NORTH, - [DIR_NORTHEAST] = ANIM_STD_GO_FAST_NORTH, + [DIR_SOUTHWEST] = ANIM_STD_GO_FAST_WEST, + [DIR_SOUTHEAST] = ANIM_STD_GO_FAST_EAST, + [DIR_NORTHWEST] = ANIM_STD_GO_FAST_WEST, + [DIR_NORTHEAST] = ANIM_STD_GO_FAST_EAST, }; static const u8 sMoveDirectionFasterAnimNums[] = { [DIR_NONE] = ANIM_STD_GO_FASTER_SOUTH, @@ -777,10 +779,10 @@ static const u8 sMoveDirectionFasterAnimNums[] = { [DIR_NORTH] = ANIM_STD_GO_FASTER_NORTH, [DIR_WEST] = ANIM_STD_GO_FASTER_WEST, [DIR_EAST] = ANIM_STD_GO_FASTER_EAST, - [DIR_SOUTHWEST] = ANIM_STD_GO_FASTER_SOUTH, - [DIR_SOUTHEAST] = ANIM_STD_GO_FASTER_SOUTH, - [DIR_NORTHWEST] = ANIM_STD_GO_FASTER_NORTH, - [DIR_NORTHEAST] = ANIM_STD_GO_FASTER_NORTH, + [DIR_SOUTHWEST] = ANIM_STD_GO_FASTER_WEST, + [DIR_SOUTHEAST] = ANIM_STD_GO_FASTER_EAST, + [DIR_NORTHWEST] = ANIM_STD_GO_FASTER_WEST, + [DIR_NORTHEAST] = ANIM_STD_GO_FASTER_EAST, }; static const u8 sMoveDirectionFastestAnimNums[] = { [DIR_NONE] = ANIM_STD_GO_FASTEST_SOUTH, @@ -788,10 +790,10 @@ static const u8 sMoveDirectionFastestAnimNums[] = { [DIR_NORTH] = ANIM_STD_GO_FASTEST_NORTH, [DIR_WEST] = ANIM_STD_GO_FASTEST_WEST, [DIR_EAST] = ANIM_STD_GO_FASTEST_EAST, - [DIR_SOUTHWEST] = ANIM_STD_GO_FASTEST_SOUTH, - [DIR_SOUTHEAST] = ANIM_STD_GO_FASTEST_SOUTH, - [DIR_NORTHWEST] = ANIM_STD_GO_FASTEST_NORTH, - [DIR_NORTHEAST] = ANIM_STD_GO_FASTEST_NORTH, + [DIR_SOUTHWEST] = ANIM_STD_GO_FASTEST_WEST, + [DIR_SOUTHEAST] = ANIM_STD_GO_FASTEST_EAST, + [DIR_NORTHWEST] = ANIM_STD_GO_FASTEST_WEST, + [DIR_NORTHEAST] = ANIM_STD_GO_FASTEST_EAST, }; static const u8 sJumpSpecialDirectionAnimNums[] = { // used for jumping onto surf mon [DIR_NONE] = ANIM_GET_ON_OFF_POKEMON_SOUTH, @@ -810,10 +812,10 @@ static const u8 sAcroWheelieDirectionAnimNums[] = { [DIR_NORTH] = ANIM_BUNNY_HOP_BACK_WHEEL_NORTH, [DIR_WEST] = ANIM_BUNNY_HOP_BACK_WHEEL_WEST, [DIR_EAST] = ANIM_BUNNY_HOP_BACK_WHEEL_EAST, - [DIR_SOUTHWEST] = ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH, - [DIR_SOUTHEAST] = ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH, - [DIR_NORTHWEST] = ANIM_BUNNY_HOP_BACK_WHEEL_NORTH, - [DIR_NORTHEAST] = ANIM_BUNNY_HOP_BACK_WHEEL_NORTH, + [DIR_SOUTHWEST] = ANIM_BUNNY_HOP_BACK_WHEEL_WEST, + [DIR_SOUTHEAST] = ANIM_BUNNY_HOP_BACK_WHEEL_EAST, + [DIR_NORTHWEST] = ANIM_BUNNY_HOP_BACK_WHEEL_WEST, + [DIR_NORTHEAST] = ANIM_BUNNY_HOP_BACK_WHEEL_EAST, }; static const u8 sAcroUnusedDirectionAnimNums[] = { [DIR_NONE] = ANIM_BUNNY_HOP_FRONT_WHEEL_SOUTH, @@ -832,10 +834,10 @@ static const u8 sAcroEndWheelieDirectionAnimNums[] = { [DIR_NORTH] = ANIM_STANDING_WHEELIE_BACK_WHEEL_NORTH, [DIR_WEST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_WEST, [DIR_EAST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_EAST, - [DIR_SOUTHWEST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_SOUTH, - [DIR_SOUTHEAST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_SOUTH, - [DIR_NORTHWEST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_NORTH, - [DIR_NORTHEAST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_NORTH, + [DIR_SOUTHWEST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_WEST, + [DIR_SOUTHEAST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_EAST, + [DIR_NORTHWEST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_WEST, + [DIR_NORTHEAST] = ANIM_STANDING_WHEELIE_BACK_WHEEL_EAST, }; static const u8 sAcroUnusedActionDirectionAnimNums[] = { [DIR_NONE] = ANIM_STANDING_WHEELIE_FRONT_WHEEL_SOUTH, @@ -854,10 +856,10 @@ static const u8 sAcroWheeliePedalDirectionAnimNums[] = { [DIR_NORTH] = ANIM_MOVING_WHEELIE_NORTH, [DIR_WEST] = ANIM_MOVING_WHEELIE_WEST, [DIR_EAST] = ANIM_MOVING_WHEELIE_EAST, - [DIR_SOUTHWEST] = ANIM_MOVING_WHEELIE_SOUTH, - [DIR_SOUTHEAST] = ANIM_MOVING_WHEELIE_SOUTH, - [DIR_NORTHWEST] = ANIM_MOVING_WHEELIE_NORTH, - [DIR_NORTHEAST] = ANIM_MOVING_WHEELIE_NORTH, + [DIR_SOUTHWEST] = ANIM_MOVING_WHEELIE_WEST, + [DIR_SOUTHEAST] = ANIM_MOVING_WHEELIE_EAST, + [DIR_NORTHWEST] = ANIM_MOVING_WHEELIE_WEST, + [DIR_NORTHEAST] = ANIM_MOVING_WHEELIE_EAST, }; static const u8 sFishingDirectionAnimNums[] = { [DIR_NONE] = ANIM_TAKE_OUT_ROD_SOUTH, @@ -898,10 +900,10 @@ static const u8 sRunningDirectionAnimNums[] = { [DIR_NORTH] = ANIM_RUN_NORTH, [DIR_WEST] = ANIM_RUN_WEST, [DIR_EAST] = ANIM_RUN_EAST, - [DIR_SOUTHWEST] = ANIM_RUN_SOUTH, - [DIR_SOUTHEAST] = ANIM_RUN_SOUTH, - [DIR_NORTHWEST] = ANIM_RUN_NORTH, - [DIR_NORTHEAST] = ANIM_RUN_NORTH, + [DIR_SOUTHWEST] = ANIM_RUN_WEST, + [DIR_SOUTHEAST] = ANIM_RUN_EAST, + [DIR_NORTHWEST] = ANIM_RUN_WEST, + [DIR_NORTHEAST] = ANIM_RUN_EAST, }; const u8 gTrainerFacingDirectionMovementTypes[] = { @@ -939,64 +941,72 @@ static const struct Coords16 sDirectionToVectors[] = { {-1, 1}, { 1, 1}, {-1, -1}, - { 1, -1} + { 1, -1}, + {-2, 1}, + { 2, 1}, + {-2, -1}, + { 2, -1} }; const u8 gFaceDirectionMovementActions[] = { - MOVEMENT_ACTION_FACE_DOWN, - MOVEMENT_ACTION_FACE_DOWN, - MOVEMENT_ACTION_FACE_UP, - MOVEMENT_ACTION_FACE_LEFT, - MOVEMENT_ACTION_FACE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_FACE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_FACE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_FACE_UP, + [DIR_WEST] = MOVEMENT_ACTION_FACE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_FACE_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_FACE_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_FACE_RIGHT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_FACE_LEFT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_FACE_RIGHT }; const u8 gWalkSlowMovementActions[] = { - MOVEMENT_ACTION_WALK_SLOW_DOWN, - MOVEMENT_ACTION_WALK_SLOW_DOWN, - MOVEMENT_ACTION_WALK_SLOW_UP, - MOVEMENT_ACTION_WALK_SLOW_LEFT, - MOVEMENT_ACTION_WALK_SLOW_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_WALK_SLOW_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_WALK_SLOW_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_WALK_SLOW_UP, + [DIR_WEST] = MOVEMENT_ACTION_WALK_SLOW_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_WALK_SLOW_RIGHT, }; const u8 gWalkNormalMovementActions[] = { - MOVEMENT_ACTION_WALK_NORMAL_DOWN, - MOVEMENT_ACTION_WALK_NORMAL_DOWN, - MOVEMENT_ACTION_WALK_NORMAL_UP, - MOVEMENT_ACTION_WALK_NORMAL_LEFT, - MOVEMENT_ACTION_WALK_NORMAL_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_WALK_NORMAL_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_WALK_NORMAL_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_WALK_NORMAL_UP, + [DIR_WEST] = MOVEMENT_ACTION_WALK_NORMAL_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_WALK_NORMAL_RIGHT, }; const u8 gWalkFastMovementActions[] = { - MOVEMENT_ACTION_WALK_FAST_DOWN, - MOVEMENT_ACTION_WALK_FAST_DOWN, - MOVEMENT_ACTION_WALK_FAST_UP, - MOVEMENT_ACTION_WALK_FAST_LEFT, - MOVEMENT_ACTION_WALK_FAST_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_WALK_FAST_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_WALK_FAST_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_WALK_FAST_UP, + [DIR_WEST] = MOVEMENT_ACTION_WALK_FAST_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_WALK_FAST_RIGHT, }; const u8 gRideWaterCurrentMovementActions[] = { - MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN, - MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN, - MOVEMENT_ACTION_RIDE_WATER_CURRENT_UP, - MOVEMENT_ACTION_RIDE_WATER_CURRENT_LEFT, - MOVEMENT_ACTION_RIDE_WATER_CURRENT_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_RIDE_WATER_CURRENT_UP, + [DIR_WEST] = MOVEMENT_ACTION_RIDE_WATER_CURRENT_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_RIDE_WATER_CURRENT_RIGHT, }; const u8 gWalkFasterMovementActions[] = { - MOVEMENT_ACTION_WALK_FASTER_DOWN, - MOVEMENT_ACTION_WALK_FASTER_DOWN, - MOVEMENT_ACTION_WALK_FASTER_UP, - MOVEMENT_ACTION_WALK_FASTER_LEFT, - MOVEMENT_ACTION_WALK_FASTER_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_WALK_FASTER_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_WALK_FASTER_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_WALK_FASTER_UP, + [DIR_WEST] = MOVEMENT_ACTION_WALK_FASTER_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_WALK_FASTER_RIGHT, }; const u8 gSlideMovementActions[] = { - MOVEMENT_ACTION_SLIDE_DOWN, - MOVEMENT_ACTION_SLIDE_DOWN, - MOVEMENT_ACTION_SLIDE_UP, - MOVEMENT_ACTION_SLIDE_LEFT, - MOVEMENT_ACTION_SLIDE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_SLIDE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_SLIDE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_SLIDE_UP, + [DIR_WEST] = MOVEMENT_ACTION_SLIDE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_SLIDE_RIGHT, }; const u8 gPlayerRunMovementActions[] = { - MOVEMENT_ACTION_PLAYER_RUN_DOWN, - MOVEMENT_ACTION_PLAYER_RUN_DOWN, - MOVEMENT_ACTION_PLAYER_RUN_UP, - MOVEMENT_ACTION_PLAYER_RUN_LEFT, - MOVEMENT_ACTION_PLAYER_RUN_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_PLAYER_RUN_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_PLAYER_RUN_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_PLAYER_RUN_UP, + [DIR_WEST] = MOVEMENT_ACTION_PLAYER_RUN_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_PLAYER_RUN_RIGHT, }; const u8 gJump2MovementActions[] = { MOVEMENT_ACTION_JUMP_2_DOWN, @@ -1034,102 +1044,170 @@ const u8 gJumpSpecialMovementActions[] = { MOVEMENT_ACTION_JUMP_SPECIAL_RIGHT, }; const u8 gWalkInPlaceSlowMovementActions[] = { - MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_DOWN, - MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_DOWN, - MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_UP, - MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_LEFT, - MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_UP, + [DIR_WEST] = MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_LEFT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_RIGHT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_WALK_IN_PLACE_SLOW_RIGHT }; const u8 gWalkInPlaceNormalMovementActions[] = { - MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_DOWN, - MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_DOWN, - MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_UP, - MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_LEFT, - MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_UP, + [DIR_WEST] = MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_LEFT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_RIGHT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_RIGHT }; const u8 gWalkInPlaceFastMovementActions[] = { - MOVEMENT_ACTION_WALK_IN_PLACE_FAST_DOWN, - MOVEMENT_ACTION_WALK_IN_PLACE_FAST_DOWN, - MOVEMENT_ACTION_WALK_IN_PLACE_FAST_UP, - MOVEMENT_ACTION_WALK_IN_PLACE_FAST_LEFT, - MOVEMENT_ACTION_WALK_IN_PLACE_FAST_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_WALK_IN_PLACE_FAST_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_WALK_IN_PLACE_FAST_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_WALK_IN_PLACE_FAST_UP, + [DIR_WEST] = MOVEMENT_ACTION_WALK_IN_PLACE_FAST_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_WALK_IN_PLACE_FAST_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_WALK_IN_PLACE_FAST_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_WALK_IN_PLACE_FAST_LEFT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_WALK_IN_PLACE_FAST_RIGHT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_WALK_IN_PLACE_FAST_RIGHT }; const u8 gWalkInPlaceFasterMovementActions[] = { - MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_DOWN, - MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_DOWN, - MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_UP, - MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_LEFT, - MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_UP, + [DIR_WEST] = MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_LEFT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_RIGHT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_WALK_IN_PLACE_FASTER_RIGHT }; const u8 gAcroWheelieFaceDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_WHEELIE_FACE_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_FACE_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_FACE_UP, - MOVEMENT_ACTION_ACRO_WHEELIE_FACE_LEFT, - MOVEMENT_ACTION_ACRO_WHEELIE_FACE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_WHEELIE_FACE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_WHEELIE_FACE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_WHEELIE_FACE_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_WHEELIE_FACE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_WHEELIE_FACE_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_FACE_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_FACE_LEFT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_FACE_RIGHT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_FACE_RIGHT }; const u8 gAcroPopWheelieFaceDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_POP_WHEELIE_DOWN, - MOVEMENT_ACTION_ACRO_POP_WHEELIE_DOWN, - MOVEMENT_ACTION_ACRO_POP_WHEELIE_UP, - MOVEMENT_ACTION_ACRO_POP_WHEELIE_LEFT, - MOVEMENT_ACTION_ACRO_POP_WHEELIE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_RIGHT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_RIGHT, }; const u8 gAcroEndWheelieFaceDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_DOWN, - MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_DOWN, - MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_UP, - MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_LEFT, - MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_RIGHT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_FACE_RIGHT, }; const u8 gAcroWheelieHopFaceDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_UP, - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_LEFT, - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_RIGHT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_FACE_RIGHT, }; const u8 gAcroWheelieHopDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_UP, - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_LEFT, - MOVEMENT_ACTION_ACRO_WHEELIE_HOP_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_RIGHT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_HOP_RIGHT, }; const u8 gAcroWheelieJumpDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_UP, - MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_LEFT, - MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_RIGHT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_RIGHT, }; const u8 gAcroWheelieInPlaceDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_UP, - MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_LEFT, - MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_RIGHT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_IN_PLACE_RIGHT, }; const u8 gAcroPopWheelieMoveDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_DOWN, - MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_DOWN, - MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_UP, - MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_LEFT, - MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_RIGHT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_RIGHT, }; const u8 gAcroWheelieMoveDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_DOWN, - MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_UP, - MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_LEFT, - MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_RIGHT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_RIGHT, }; const u8 gAcroEndWheelieMoveDirectionMovementActions[] = { - MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_DOWN, - MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_DOWN, - MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_UP, - MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_LEFT, - MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_RIGHT, + [DIR_NONE] = MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_DOWN, + [DIR_SOUTH] = MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_DOWN, + [DIR_NORTH] = MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_UP, + [DIR_WEST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_LEFT, + [DIR_EAST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_RIGHT, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_LEFT, + [DIR_NORTHWEST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_LEFT, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_RIGHT, + [DIR_NORTHEAST] = MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_RIGHT, +}; +// run slow +const u8 gRunSlowMovementActions[] = { + [DIR_NONE] = MOVEMENT_ACTION_RUN_DOWN_SLOW, + [DIR_SOUTH] = MOVEMENT_ACTION_RUN_DOWN_SLOW, + [DIR_NORTH] = MOVEMENT_ACTION_RUN_UP_SLOW, + [DIR_WEST] = MOVEMENT_ACTION_RUN_LEFT_SLOW, + [DIR_EAST] = MOVEMENT_ACTION_RUN_RIGHT_SLOW, + [DIR_SOUTHWEST] = MOVEMENT_ACTION_RUN_LEFT_SLOW, + [DIR_SOUTHEAST] = MOVEMENT_ACTION_RUN_RIGHT_SLOW, + [DIR_NORTHWEST] = MOVEMENT_ACTION_RUN_LEFT_SLOW, + [DIR_NORTHEAST] = MOVEMENT_ACTION_RUN_RIGHT_SLOW, }; static const u8 sOppositeDirections[] = { @@ -1298,7 +1376,7 @@ static u8 GetObjectEventIdByLocalIdAndMapInternal(u8 localId, u8 mapNum, u8 mapG return OBJECT_EVENTS_COUNT; } -static u8 GetObjectEventIdByLocalId(u8 localId) +u8 GetObjectEventIdByLocalId(u8 localId) { u8 i; for (i = 0; i < OBJECT_EVENTS_COUNT; i++) @@ -2133,7 +2211,7 @@ void RemoveFollowingPokemon(void) } // Determine whether follower *should* be visible -static bool32 IsFollowerVisible(void) +bool32 IsFollowerVisible(void) { return !(TestPlayerAvatarFlags(FOLLOWER_INVISIBLE_FLAGS) || MetatileBehavior_IsSurfableWaterOrUnderwater(gObjectEvents[gPlayerAvatar.objectEventId].previousMetatileBehavior) @@ -5328,16 +5406,11 @@ bool8 MovementType_FollowPlayer_Active(struct ObjectEvent *objectEvent, struct S bool8 MovementType_FollowPlayer_Moving(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - #ifdef MB_SIDEWAYS_STAIRS_RIGHT_SIDE // Copied from ObjectEventExecSingleMovementAction if (gMovementActionFuncs[objectEvent->movementActionId][sprite->sActionFuncId](objectEvent, sprite)) { objectEvent->movementActionId = MOVEMENT_ACTION_NONE; sprite->sActionFuncId = 0; - #else - if (ObjectEventExecSingleMovementAction(objectEvent, sprite)) - { - #endif objectEvent->singleMovementActive = 0; if (sprite->sTypeFuncId) // restore nonzero state sprite->sTypeFuncId = 1; @@ -5381,10 +5454,8 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri s16 y; s16 targetX; s16 targetY; - #ifdef MB_SIDEWAYS_STAIRS_RIGHT_SIDE u32 playerAction = gObjectEvents[gPlayerAvatar.objectEventId].movementActionId; - #endif - + targetX = gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.x; targetY = gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.y; x = gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x; @@ -5423,12 +5494,12 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri // Follow player direction = GetDirectionToFace(x, y, targetX, targetY); MoveCoords(direction, &x, &y); - #ifdef MB_SIDEWAYS_STAIRS_RIGHT_SIDE // https://github.com/ghoulslash/pokeemerald/tree/sideways_stairs GetCollisionAtCoords(objectEvent, x, y, direction); // Sets directionOverwrite for stairs if (GetLedgeJumpDirection(x, y, direction) != DIR_NONE) { // InitJumpRegular will set the proper speed ObjectEventSetSingleMovement(objectEvent, sprite, GetJump2MovementAction(direction)); + } else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) { // Set follow speed according to player's speed @@ -5455,29 +5526,6 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri } } sprite->sActionFuncId = 0; - #else - if (GetLedgeJumpDirection(x, y, direction) != DIR_NONE) - { - // InitJumpRegular will set the proper speed - ObjectEventSetSingleMovement(objectEvent, sprite, GetJump2MovementAction(direction)); - } - else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) - { - // Set follow speed according to player's speed - ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkFastMovementAction(direction)); - } - else if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2) - { - // If *player* jumps, make step take twice as long - ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(direction)); - } - else - { - ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkNormalMovementAction(direction)); - if (OW_FOLLOWERS_BOBBING == TRUE) - sprite->y2 = -1; - } - #endif objectEvent->singleMovementActive = 1; sprite->sTypeFuncId = 2; return TRUE; @@ -5920,7 +5968,7 @@ u8 GetTrainerFacingDirectionMovementType(u8 direction) return gTrainerFacingDirectionMovementTypes[direction]; } -static u8 GetCollisionInDirection(struct ObjectEvent *objectEvent, u8 direction) +u8 GetCollisionInDirection(struct ObjectEvent *objectEvent, u8 direction) { s16 x = objectEvent->currentCoords.x; s16 y = objectEvent->currentCoords.y; @@ -5928,18 +5976,56 @@ static u8 GetCollisionInDirection(struct ObjectEvent *objectEvent, u8 direction) return GetCollisionAtCoords(objectEvent, x, y, direction); } -u8 GetCollisionAtCoords(struct ObjectEvent *objectEvent, s16 x, s16 y, u32 dir) +u8 GetSidewaysStairsCollision(struct ObjectEvent *objectEvent, u8 dir, u8 currentBehavior, u8 nextBehavior, u8 collision) { - u8 direction = dir; - -#if OW_FLAG_NO_COLLISION != 0 - if (FlagGet(OW_FLAG_NO_COLLISION)) - return COLLISION_NONE; -#endif + if ((dir == DIR_SOUTH || dir == DIR_NORTH) && collision != COLLISION_NONE) + return collision; + + // cant descend stairs into water + if (MetatileBehavior_IsSurfableFishableWater(nextBehavior)) + return collision; + + if (MetatileBehavior_IsSidewaysStairsLeftSide(nextBehavior)) + { + //moving ONTO left side stair + if (dir == DIR_WEST && currentBehavior != nextBehavior) + return collision; //moving onto top part of left-stair going left, so no diagonal + else + return COLLISION_SIDEWAYS_STAIRS_TO_LEFT; // move diagonally + } + else if (MetatileBehavior_IsSidewaysStairsRightSide(nextBehavior)) + { + //moving ONTO right side stair + if (dir == DIR_EAST && currentBehavior != nextBehavior) + return collision; //moving onto top part of right-stair going right, so no diagonal + else + return COLLISION_SIDEWAYS_STAIRS_TO_RIGHT; + } + else if (MetatileBehavior_IsSidewaysStairsLeftSideAny(currentBehavior)) + { + //moving OFF of any left side stair + if (dir == DIR_WEST && nextBehavior != currentBehavior) + return COLLISION_SIDEWAYS_STAIRS_TO_LEFT; //moving off of left stairs onto non-stair -> move diagonal + else + return collision; //moving off of left side stair to east -> move east + } + else if (MetatileBehavior_IsSidewaysStairsRightSideAny(currentBehavior)) + { + //moving OFF of any right side stair + if (dir == DIR_EAST && nextBehavior != currentBehavior) + return COLLISION_SIDEWAYS_STAIRS_TO_RIGHT; //moving off right stair onto non-stair -> move diagonal + else + return collision; + } + + return collision; +} +static u8 GetVanillaCollision(struct ObjectEvent *objectEvent, s16 x, s16 y, u8 direction) +{ if (IsCoordOutsideObjectEventMovementRange(objectEvent, x, y)) return COLLISION_OUTSIDE_RANGE; - else if (MapGridGetCollisionAt(x, y) || GetMapBorderIdAt(x, y) == CONNECTION_INVALID || IsMetatileDirectionallyImpassable(objectEvent, x, y, direction)) + else if (MapGridGetCollisionAt(x, y) || GetMapBorderIdAt(x, y) == -1 || IsMetatileDirectionallyImpassable(objectEvent, x, y, direction)) return COLLISION_IMPASSABLE; else if (objectEvent->trackedByCamera && !CanCameraMoveInDirection(direction)) return COLLISION_IMPASSABLE; @@ -5947,9 +6033,95 @@ u8 GetCollisionAtCoords(struct ObjectEvent *objectEvent, s16 x, s16 y, u32 dir) return COLLISION_ELEVATION_MISMATCH; else if (DoesObjectCollideWithObjectAt(objectEvent, x, y)) return COLLISION_OBJECT_EVENT; + return COLLISION_NONE; } +static bool8 ObjectEventOnLeftSideStair(struct ObjectEvent *objectEvent, s16 x, s16 y, u8 direction) +{ + switch (direction) + { + case DIR_EAST: + MoveCoords(DIR_NORTH, &x, &y); + return DoesObjectCollideWithObjectAt(objectEvent, x, y); + case DIR_WEST: + MoveCoords(DIR_SOUTH, &x, &y); + return DoesObjectCollideWithObjectAt(objectEvent, x, y); + default: + return FALSE; //north/south taken care of in GetVanillaCollision + } +} + +static bool8 ObjectEventOnRightSideStair(struct ObjectEvent *objectEvent, s16 x, s16 y, u8 direction) +{ + switch (direction) + { + case DIR_EAST: + MoveCoords(DIR_SOUTH, &x, &y); + return DoesObjectCollideWithObjectAt(objectEvent, x, y); + case DIR_WEST: + MoveCoords(DIR_NORTH, &x, &y); + return DoesObjectCollideWithObjectAt(objectEvent, x, y); + default: + return FALSE; //north/south taken care of in GetVanillaCollision + } +} + +u8 GetCollisionAtCoords(struct ObjectEvent *objectEvent, s16 x, s16 y, u32 dir) +{ + u8 direction = dir; + u8 currentBehavior = MapGridGetMetatileBehaviorAt(objectEvent->currentCoords.x, objectEvent->currentCoords.y); + u8 nextBehavior = MapGridGetMetatileBehaviorAt(x, y); + u8 collision; + + #if OW_FLAG_NO_COLLISION != 0 + if (FlagGet(OW_FLAG_NO_COLLISION)) + return COLLISION_NONE; + #endif + + objectEvent->directionOverwrite = DIR_NONE; + + //sideways stairs checks + if (MetatileBehavior_IsSidewaysStairsLeftSideTop(nextBehavior) && dir == DIR_EAST) + return COLLISION_IMPASSABLE; //moving onto left-side top edge east from regular ground -> nope + else if (MetatileBehavior_IsSidewaysStairsRightSideTop(nextBehavior) && dir == DIR_WEST) + return COLLISION_IMPASSABLE; //moving onto left-side top edge east from regular ground -> nope + else if (MetatileBehavior_IsSidewaysStairsRightSideBottom(nextBehavior) && (dir == DIR_EAST || dir == DIR_SOUTH)) + return COLLISION_IMPASSABLE; //moving into right-side bottom edge from regular ground -> nah + else if (MetatileBehavior_IsSidewaysStairsLeftSideBottom(nextBehavior) && (dir == DIR_WEST || dir == DIR_SOUTH)) + return COLLISION_IMPASSABLE; //moving onto left-side bottom edge from regular ground -> nah + else if ((MetatileBehavior_IsSidewaysStairsLeftSideTop(currentBehavior) || MetatileBehavior_IsSidewaysStairsRightSideTop(currentBehavior)) + && dir == DIR_NORTH) + return COLLISION_IMPASSABLE; //trying to move north off of top-most tile onto same level doesn't work + else if (!(MetatileBehavior_IsSidewaysStairsLeftSideTop(currentBehavior) || MetatileBehavior_IsSidewaysStairsRightSideTop(currentBehavior)) + && dir == DIR_SOUTH && (MetatileBehavior_IsSidewaysStairsLeftSideTop(nextBehavior) || MetatileBehavior_IsSidewaysStairsRightSideTop(nextBehavior))) + return COLLISION_IMPASSABLE; //trying to move south onto top stair tile at same level from non-stair -> no + else if (!(MetatileBehavior_IsSidewaysStairsLeftSideBottom(currentBehavior) || MetatileBehavior_IsSidewaysStairsRightSideBottom(currentBehavior)) + && dir == DIR_NORTH && (MetatileBehavior_IsSidewaysStairsLeftSideBottom(nextBehavior) || MetatileBehavior_IsSidewaysStairsRightSideBottom(nextBehavior))) + return COLLISION_IMPASSABLE; //trying to move north onto top stair tile at same level from non-stair -> no + + // regular checks + collision = GetVanillaCollision(objectEvent, x, y, dir); + + //sideways stairs direction change checks + collision = GetSidewaysStairsCollision(objectEvent, dir, currentBehavior, nextBehavior, collision); + switch (collision) + { + case COLLISION_SIDEWAYS_STAIRS_TO_LEFT: + if (ObjectEventOnLeftSideStair(objectEvent, x, y, dir)) + return COLLISION_OBJECT_EVENT; + objectEvent->directionOverwrite = GetLeftSideStairsDirection(dir); + return COLLISION_NONE; + case COLLISION_SIDEWAYS_STAIRS_TO_RIGHT: + if (ObjectEventOnRightSideStair(objectEvent, x, y, dir)) + return COLLISION_OBJECT_EVENT; + objectEvent->directionOverwrite = GetRightSideStairsDirection(dir); + return COLLISION_NONE; + } + + return collision; +} + u8 GetCollisionFlagsAtCoords(struct ObjectEvent *objectEvent, s16 x, s16 y, u8 direction) { u8 flags = 0; @@ -6013,6 +6185,7 @@ static bool8 DoesObjectCollideWithObjectAt(struct ObjectEvent *objectEvent, s16 curObject = &gObjectEvents[i]; if (curObject->active && (curObject->movementType != MOVEMENT_TYPE_FOLLOW_PLAYER || objectEvent != &gObjectEvents[gPlayerAvatar.objectEventId]) && curObject != objectEvent) { + // check for collision if curObject is active, not the object in question, and not exempt from collisions if ((curObject->currentCoords.x == x && curObject->currentCoords.y == y) || (curObject->previousCoords.x == x && curObject->previousCoords.y == y)) { if (AreElevationsCompatible(objectEvent->currentElevation, curObject->currentElevation)) @@ -6149,10 +6322,35 @@ bool8 ObjectEventIsHeldMovementActive(struct ObjectEvent *objectEvent) return FALSE; } +static u8 TryUpdateMovementActionOnStairs(struct ObjectEvent *objectEvent, u8 movementActionId) +{ + if (objectEvent->isPlayer || objectEvent->localId == OBJ_EVENT_ID_FOLLOWER) + return movementActionId; // handled separately + + if (!ObjectMovingOnRockStairs(objectEvent, objectEvent->movementDirection)) + return movementActionId; + + switch (movementActionId) + { + case MOVEMENT_ACTION_WALK_NORMAL_DOWN: + return MOVEMENT_ACTION_WALK_SLOW_DOWN; + case MOVEMENT_ACTION_WALK_NORMAL_UP: + return MOVEMENT_ACTION_WALK_SLOW_UP; + case MOVEMENT_ACTION_WALK_NORMAL_LEFT: + return MOVEMENT_ACTION_WALK_SLOW_LEFT; + case MOVEMENT_ACTION_WALK_NORMAL_RIGHT: + return MOVEMENT_ACTION_WALK_SLOW_RIGHT; + default: + return movementActionId; + } +} + bool8 ObjectEventSetHeldMovement(struct ObjectEvent *objectEvent, u8 movementActionId) { if (ObjectEventIsMovementOverridden(objectEvent)) return TRUE; + + movementActionId = TryUpdateMovementActionOnStairs(objectEvent, movementActionId); UnfreezeObjectEvent(objectEvent); objectEvent->movementActionId = movementActionId; @@ -6164,6 +6362,7 @@ bool8 ObjectEventSetHeldMovement(struct ObjectEvent *objectEvent, u8 movementAct void ObjectEventForceSetHeldMovement(struct ObjectEvent *objectEvent, u8 movementActionId) { + movementActionId = TryUpdateMovementActionOnStairs(objectEvent, movementActionId); ObjectEventClearHeldMovementIfActive(objectEvent); ObjectEventSetHeldMovement(objectEvent, movementActionId); } @@ -6203,7 +6402,7 @@ u8 ObjectEventClearHeldMovementIfFinished(struct ObjectEvent *objectEvent) u8 ObjectEventGetHeldMovementActionId(struct ObjectEvent *objectEvent) { if (objectEvent->heldMovementActive) - return objectEvent->movementActionId; + return TryUpdateMovementActionOnStairs(objectEvent, objectEvent->movementActionId); return MOVEMENT_ACTION_NONE; } @@ -6232,12 +6431,13 @@ u8 name(u32 idx)\ u8 animIds[sizeof(table)];\ direction = idx;\ memcpy(animIds, (table), sizeof(table));\ - if (direction > DIR_EAST) direction = 0;\ + if (direction > sizeof(table)) direction = 0;\ return animIds[direction];\ } dirn_to_anim(GetFaceDirectionMovementAction, gFaceDirectionMovementActions); dirn_to_anim(GetWalkSlowMovementAction, gWalkSlowMovementActions); +dirn_to_anim(GetPlayerRunSlowMovementAction, gRunSlowMovementActions); dirn_to_anim(GetWalkNormalMovementAction, gWalkNormalMovementActions); dirn_to_anim(GetWalkFastMovementAction, gWalkFastMovementActions); dirn_to_anim(GetRideWaterCurrentMovementAction, gRideWaterCurrentMovementActions); @@ -6306,12 +6506,14 @@ static u32 GetCopyDirection(u8 copyInitDir, u32 playerInitDir, u32 playerMoveDir static void ObjectEventExecHeldMovementAction(struct ObjectEvent *objectEvent, struct Sprite *sprite) { + objectEvent->movementActionId = TryUpdateMovementActionOnStairs(objectEvent, objectEvent->movementActionId); if (gMovementActionFuncs[objectEvent->movementActionId][sprite->sActionFuncId](objectEvent, sprite)) objectEvent->heldMovementFinished = TRUE; } static bool8 ObjectEventExecSingleMovementAction(struct ObjectEvent *objectEvent, struct Sprite *sprite) { + objectEvent->movementActionId = TryUpdateMovementActionOnStairs(objectEvent, objectEvent->movementActionId); if (gMovementActionFuncs[objectEvent->movementActionId][sprite->sActionFuncId](objectEvent, sprite)) { objectEvent->movementActionId = MOVEMENT_ACTION_NONE; @@ -6323,7 +6525,7 @@ static bool8 ObjectEventExecSingleMovementAction(struct ObjectEvent *objectEvent static void ObjectEventSetSingleMovement(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8 animId) { - objectEvent->movementActionId = animId; + objectEvent->movementActionId = TryUpdateMovementActionOnStairs(objectEvent, animId); sprite->sActionFuncId = 0; } @@ -6539,7 +6741,10 @@ bool8 MovementAction_WalkSlowUp_Step1(struct ObjectEvent *objectEvent, struct Sp bool8 MovementAction_WalkSlowLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitWalkSlow(objectEvent, sprite, DIR_WEST); + if (objectEvent->directionOverwrite) + InitWalkSlow(objectEvent, sprite, objectEvent->directionOverwrite); + else + InitWalkSlow(objectEvent, sprite, DIR_WEST); return MovementAction_WalkSlowLeft_Step1(objectEvent, sprite); } @@ -6555,7 +6760,10 @@ bool8 MovementAction_WalkSlowLeft_Step1(struct ObjectEvent *objectEvent, struct bool8 MovementAction_WalkSlowRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitWalkSlow(objectEvent, sprite, DIR_EAST); + if (objectEvent->directionOverwrite) + InitWalkSlow(objectEvent, sprite, objectEvent->directionOverwrite); + else + InitWalkSlow(objectEvent, sprite, DIR_EAST); return MovementAction_WalkSlowRight_Step1(objectEvent, sprite); } @@ -6667,7 +6875,10 @@ bool8 MovementAction_WalkNormalUp_Step1(struct ObjectEvent *objectEvent, struct bool8 MovementAction_WalkNormalLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_NORMAL); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_NORMAL); + else + InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_NORMAL); return MovementAction_WalkNormalLeft_Step1(objectEvent, sprite); } @@ -6683,7 +6894,10 @@ bool8 MovementAction_WalkNormalLeft_Step1(struct ObjectEvent *objectEvent, struc bool8 MovementAction_WalkNormalRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_NORMAL); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_NORMAL); + else + InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_NORMAL); return MovementAction_WalkNormalRight_Step1(objectEvent, sprite); } @@ -6961,7 +7175,10 @@ bool8 MovementAction_WalkFastUp_Step1(struct ObjectEvent *objectEvent, struct Sp bool8 MovementAction_WalkFastLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_FAST_1); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_FAST_1); + else + InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_FAST_1); return MovementAction_WalkFastLeft_Step1(objectEvent, sprite); } @@ -6977,7 +7194,10 @@ bool8 MovementAction_WalkFastLeft_Step1(struct ObjectEvent *objectEvent, struct bool8 MovementAction_WalkFastRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_FAST_1); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_FAST_1); + else + InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_FAST_1); return MovementAction_WalkFastRight_Step1(objectEvent, sprite); } @@ -7311,13 +7531,19 @@ bool8 MovementAction_WalkInPlaceFasterUp_Step0(struct ObjectEvent *objectEvent, bool8 MovementAction_WalkInPlaceFasterLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMoveInPlace(objectEvent, sprite, DIR_WEST, GetMoveDirectionFasterAnimNum(DIR_WEST), 4); + if (objectEvent->directionOverwrite) + InitMoveInPlace(objectEvent, sprite, objectEvent->directionOverwrite, GetMoveDirectionFasterAnimNum(DIR_WEST), 4); + else + InitMoveInPlace(objectEvent, sprite, DIR_WEST, GetMoveDirectionFasterAnimNum(DIR_WEST), 4); return MovementAction_WalkInPlace_Step1(objectEvent, sprite); } bool8 MovementAction_WalkInPlaceFasterRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMoveInPlace(objectEvent, sprite, DIR_EAST, GetMoveDirectionFasterAnimNum(DIR_EAST), 4); + if (objectEvent->directionOverwrite) + InitMoveInPlace(objectEvent, sprite, objectEvent->directionOverwrite, GetMoveDirectionFasterAnimNum(DIR_EAST), 4); + else + InitMoveInPlace(objectEvent, sprite, DIR_EAST, GetMoveDirectionFasterAnimNum(DIR_EAST), 4); return MovementAction_WalkInPlace_Step1(objectEvent, sprite); } @@ -7355,7 +7581,10 @@ bool8 MovementAction_RideWaterCurrentUp_Step1(struct ObjectEvent *objectEvent, s bool8 MovementAction_RideWaterCurrentLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_FAST_2); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_FAST_2); + else + InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_FAST_2); return MovementAction_RideWaterCurrentLeft_Step1(objectEvent, sprite); } @@ -7371,7 +7600,10 @@ bool8 MovementAction_RideWaterCurrentLeft_Step1(struct ObjectEvent *objectEvent, bool8 MovementAction_RideWaterCurrentRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_FAST_2); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_FAST_2); + else + InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_FAST_2); return MovementAction_RideWaterCurrentRight_Step1(objectEvent, sprite); } @@ -7419,7 +7651,10 @@ bool8 MovementAction_WalkFasterUp_Step1(struct ObjectEvent *objectEvent, struct bool8 MovementAction_WalkFasterLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_FASTER); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_FASTER); + else + InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_FASTER); return MovementAction_WalkFasterLeft_Step1(objectEvent, sprite); } @@ -7435,7 +7670,10 @@ bool8 MovementAction_WalkFasterLeft_Step1(struct ObjectEvent *objectEvent, struc bool8 MovementAction_WalkFasterRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_FASTER); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_FASTER); + else + InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_FASTER); return MovementAction_WalkFasterRight_Step1(objectEvent, sprite); } @@ -7483,7 +7721,10 @@ bool8 MovementAction_SlideUp_Step1(struct ObjectEvent *objectEvent, struct Sprit bool8 MovementAction_SlideLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_FASTEST); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_FASTEST); + else + InitMovementNormal(objectEvent, sprite, DIR_WEST, MOVE_SPEED_FASTEST); return MovementAction_SlideLeft_Step1(objectEvent, sprite); } @@ -7499,7 +7740,10 @@ bool8 MovementAction_SlideLeft_Step1(struct ObjectEvent *objectEvent, struct Spr bool8 MovementAction_SlideRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_FASTEST); + if (objectEvent->directionOverwrite) + InitMovementNormal(objectEvent, sprite, objectEvent->directionOverwrite, MOVE_SPEED_FASTEST); + else + InitMovementNormal(objectEvent, sprite, DIR_EAST, MOVE_SPEED_FASTEST); return MovementAction_SlideRight_Step1(objectEvent, sprite); } @@ -7547,7 +7791,10 @@ bool8 MovementAction_PlayerRunUp_Step1(struct ObjectEvent *objectEvent, struct S bool8 MovementAction_PlayerRunLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - StartRunningAnim(objectEvent, sprite, DIR_WEST); + if (objectEvent->directionOverwrite) + StartRunningAnim(objectEvent, sprite, objectEvent->directionOverwrite); + else + StartRunningAnim(objectEvent, sprite, DIR_WEST); return MovementAction_PlayerRunLeft_Step1(objectEvent, sprite); } @@ -7563,7 +7810,10 @@ bool8 MovementAction_PlayerRunLeft_Step1(struct ObjectEvent *objectEvent, struct bool8 MovementAction_PlayerRunRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - StartRunningAnim(objectEvent, sprite, DIR_EAST); + if (objectEvent->directionOverwrite) + StartRunningAnim(objectEvent, sprite, objectEvent->directionOverwrite); + else + StartRunningAnim(objectEvent, sprite, DIR_EAST); return MovementAction_PlayerRunRight_Step1(objectEvent, sprite); } @@ -8450,7 +8700,10 @@ bool8 MovementAction_AcroWheelieHopUp_Step1(struct ObjectEvent *objectEvent, str bool8 MovementAction_AcroWheelieHopLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroWheelieJump(objectEvent, sprite, DIR_WEST, JUMP_DISTANCE_NORMAL, JUMP_TYPE_LOW); + if (objectEvent->directionOverwrite) + InitAcroWheelieJump(objectEvent, sprite, objectEvent->directionOverwrite, JUMP_DISTANCE_NORMAL, JUMP_TYPE_LOW); + else + InitAcroWheelieJump(objectEvent, sprite, DIR_WEST, JUMP_DISTANCE_NORMAL, JUMP_TYPE_LOW); return MovementAction_AcroWheelieHopLeft_Step1(objectEvent, sprite); } @@ -8467,7 +8720,10 @@ bool8 MovementAction_AcroWheelieHopLeft_Step1(struct ObjectEvent *objectEvent, s bool8 MovementAction_AcroWheelieHopRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroWheelieJump(objectEvent, sprite, DIR_EAST, JUMP_DISTANCE_NORMAL, JUMP_TYPE_LOW); + if (objectEvent->directionOverwrite) + InitAcroWheelieJump(objectEvent, sprite, objectEvent->directionOverwrite, JUMP_DISTANCE_NORMAL, JUMP_TYPE_LOW); + else + InitAcroWheelieJump(objectEvent, sprite, DIR_EAST, JUMP_DISTANCE_NORMAL, JUMP_TYPE_LOW); return MovementAction_AcroWheelieHopRight_Step1(objectEvent, sprite); } @@ -8518,7 +8774,10 @@ bool8 MovementAction_AcroWheelieJumpUp_Step1(struct ObjectEvent *objectEvent, st bool8 MovementAction_AcroWheelieJumpLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroWheelieJump(objectEvent, sprite, DIR_WEST, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH); + if (objectEvent->directionOverwrite) + InitAcroWheelieJump(objectEvent, sprite, objectEvent->directionOverwrite, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH); + else + InitAcroWheelieJump(objectEvent, sprite, DIR_WEST, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH); return MovementAction_AcroWheelieJumpLeft_Step1(objectEvent, sprite); } @@ -8535,7 +8794,10 @@ bool8 MovementAction_AcroWheelieJumpLeft_Step1(struct ObjectEvent *objectEvent, bool8 MovementAction_AcroWheelieJumpRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroWheelieJump(objectEvent, sprite, DIR_EAST, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH); + if (objectEvent->directionOverwrite) + InitAcroWheelieJump(objectEvent, sprite, objectEvent->directionOverwrite, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH); + else + InitAcroWheelieJump(objectEvent, sprite, DIR_EAST, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH); return MovementAction_AcroWheelieJumpRight_Step1(objectEvent, sprite); } @@ -8564,13 +8826,19 @@ bool8 MovementAction_AcroWheelieInPlaceUp_Step0(struct ObjectEvent *objectEvent, bool8 MovementAction_AcroWheelieInPlaceLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMoveInPlace(objectEvent, sprite, DIR_WEST, GetAcroWheeliePedalDirectionAnimNum(DIR_WEST), 8); + if (objectEvent->directionOverwrite) + InitMoveInPlace(objectEvent, sprite, objectEvent->directionOverwrite, GetAcroWheeliePedalDirectionAnimNum(objectEvent->directionOverwrite), 8); + else + InitMoveInPlace(objectEvent, sprite, DIR_WEST, GetAcroWheeliePedalDirectionAnimNum(DIR_WEST), 8); return MovementAction_WalkInPlace_Step1(objectEvent, sprite); } bool8 MovementAction_AcroWheelieInPlaceRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitMoveInPlace(objectEvent, sprite, DIR_EAST, GetAcroWheeliePedalDirectionAnimNum(DIR_EAST), 8); + if (objectEvent->directionOverwrite) + InitMoveInPlace(objectEvent, sprite, objectEvent->directionOverwrite, GetAcroWheeliePedalDirectionAnimNum(objectEvent->directionOverwrite), 8); + else + InitMoveInPlace(objectEvent, sprite, DIR_EAST, GetAcroWheeliePedalDirectionAnimNum(DIR_EAST), 8); return MovementAction_WalkInPlace_Step1(objectEvent, sprite); } @@ -8615,7 +8883,10 @@ bool8 MovementAction_AcroPopWheelieMoveUp_Step1(struct ObjectEvent *objectEvent, bool8 MovementAction_AcroPopWheelieMoveLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroPopWheelie(objectEvent, sprite, DIR_WEST, 1); + if (objectEvent->directionOverwrite) + InitAcroPopWheelie(objectEvent, sprite, objectEvent->directionOverwrite, 1); + else + InitAcroPopWheelie(objectEvent, sprite, DIR_WEST, 1); return MovementAction_AcroPopWheelieMoveLeft_Step1(objectEvent, sprite); } @@ -8631,7 +8902,10 @@ bool8 MovementAction_AcroPopWheelieMoveLeft_Step1(struct ObjectEvent *objectEven bool8 MovementAction_AcroPopWheelieMoveRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroPopWheelie(objectEvent, sprite, DIR_EAST, 1); + if (objectEvent->directionOverwrite) + InitAcroPopWheelie(objectEvent, sprite, objectEvent->directionOverwrite, 1); + else + InitAcroPopWheelie(objectEvent, sprite, DIR_EAST, 1); return MovementAction_AcroPopWheelieMoveRight_Step1(objectEvent, sprite); } @@ -8685,7 +8959,10 @@ bool8 MovementAction_AcroWheelieMoveUp_Step1(struct ObjectEvent *objectEvent, st bool8 MovementAction_AcroWheelieMoveLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroWheelieMove(objectEvent, sprite, DIR_WEST, 1); + if (objectEvent->directionOverwrite) + InitAcroWheelieMove(objectEvent, sprite, objectEvent->directionOverwrite, 1); + else + InitAcroWheelieMove(objectEvent, sprite, DIR_WEST, 1); return MovementAction_AcroWheelieMoveLeft_Step1(objectEvent, sprite); } @@ -8701,7 +8978,10 @@ bool8 MovementAction_AcroWheelieMoveLeft_Step1(struct ObjectEvent *objectEvent, bool8 MovementAction_AcroWheelieMoveRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroWheelieMove(objectEvent, sprite, DIR_EAST, 1); + if (objectEvent->directionOverwrite) + InitAcroWheelieMove(objectEvent, sprite, objectEvent->directionOverwrite, 1); + else + InitAcroWheelieMove(objectEvent, sprite, DIR_EAST, 1); return MovementAction_AcroWheelieMoveRight_Step1(objectEvent, sprite); } @@ -8756,7 +9036,10 @@ bool8 MovementAction_AcroEndWheelieMoveUp_Step1(struct ObjectEvent *objectEvent, bool8 MovementAction_AcroEndWheelieMoveLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroEndWheelie(objectEvent, sprite, DIR_WEST, 1); + if (objectEvent->directionOverwrite) + InitAcroEndWheelie(objectEvent, sprite, objectEvent->directionOverwrite, 1); + else + InitAcroEndWheelie(objectEvent, sprite, DIR_WEST, 1); return MovementAction_AcroEndWheelieMoveLeft_Step1(objectEvent, sprite); } @@ -8772,7 +9055,10 @@ bool8 MovementAction_AcroEndWheelieMoveLeft_Step1(struct ObjectEvent *objectEven bool8 MovementAction_AcroEndWheelieMoveRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) { - InitAcroEndWheelie(objectEvent, sprite, DIR_EAST, 1); + if (objectEvent->directionOverwrite) + InitAcroEndWheelie(objectEvent, sprite, objectEvent->directionOverwrite, 1); + else + InitAcroEndWheelie(objectEvent, sprite, DIR_EAST, 1); return MovementAction_AcroEndWheelieMoveRight_Step1(objectEvent, sprite); } @@ -8976,6 +9262,9 @@ static void GetGroundEffectFlags_LongGrassOnBeginStep(struct ObjectEvent *objEve static void GetGroundEffectFlags_Tracks(struct ObjectEvent *objEvent, u32 *flags) { + if (objEvent->directionOverwrite) + return; + if (MetatileBehavior_IsDeepSand(objEvent->previousMetatileBehavior)) *flags |= GROUND_EFFECT_FLAG_DEEP_SAND; else if (MetatileBehavior_IsSandOrDeepSand(objEvent->previousMetatileBehavior) @@ -9476,12 +9765,13 @@ static void DoTracksGroundEffect_BikeTireTracks(struct ObjectEvent *objEvent, st if (objEvent->currentCoords.x != objEvent->previousCoords.x || objEvent->currentCoords.y != objEvent->previousCoords.y) { + u8 movementDir = (objEvent->previousMovementDirection > DIR_EAST) ? (objEvent->previousMovementDirection - DIR_EAST) : objEvent->previousMovementDirection; gFieldEffectArguments[0] = objEvent->previousCoords.x; gFieldEffectArguments[1] = objEvent->previousCoords.y; gFieldEffectArguments[2] = 149; gFieldEffectArguments[3] = 2; gFieldEffectArguments[4] = - bikeTireTracks_Transitions[objEvent->previousMovementDirection][objEvent->facingDirection - 5]; + bikeTireTracks_Transitions[movementDir][objEvent->facingDirection - 5]; FieldEffectStart(FLDEFF_BIKE_TIRE_TRACKS); } } @@ -10626,3 +10916,50 @@ void GetDaycareGraphics(struct ScriptContext *ctx) } gSpecialVar_Result = i; } + +// running slow +static void StartSlowRunningAnim(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8 direction) +{ + InitNpcForWalkSlow(objectEvent, sprite, direction); + SetStepAnimHandleAlternation(objectEvent, sprite, GetRunningDirectionAnimNum(objectEvent->facingDirection)); +} + +bool8 MovementActionFunc_RunSlowDown_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) +{ + StartSlowRunningAnim(objectEvent, sprite, DIR_SOUTH); + return MovementActionFunc_RunSlow_Step1(objectEvent, sprite); +} + +bool8 MovementActionFunc_RunSlowUp_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) +{ + StartSlowRunningAnim(objectEvent, sprite, DIR_NORTH); + return MovementActionFunc_RunSlow_Step1(objectEvent, sprite); +} + +bool8 MovementActionFunc_RunSlowLeft_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) +{ + if (objectEvent->directionOverwrite) + StartSlowRunningAnim(objectEvent, sprite, objectEvent->directionOverwrite); + else + StartSlowRunningAnim(objectEvent, sprite, DIR_WEST); + return MovementActionFunc_RunSlow_Step1(objectEvent, sprite); +} + +bool8 MovementActionFunc_RunSlowRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) +{ + if (objectEvent->directionOverwrite) + StartSlowRunningAnim(objectEvent, sprite, objectEvent->directionOverwrite); + else + StartSlowRunningAnim(objectEvent, sprite, DIR_EAST); + return MovementActionFunc_RunSlow_Step1(objectEvent, sprite); +} + +bool8 MovementActionFunc_RunSlow_Step1(struct ObjectEvent *objectEvent, struct Sprite *sprite) +{ + if (UpdateMovementNormal(objectEvent, sprite)) + { + sprite->sActionFuncId = 2; + return TRUE; + } + return FALSE; +} diff --git a/src/field_control_avatar.c b/src/field_control_avatar.c index 5e709a9fb0..0a1fcf7e33 100644 --- a/src/field_control_avatar.c +++ b/src/field_control_avatar.c @@ -310,8 +310,39 @@ static const u8 *GetInteractedObjectEventScript(struct MapPosition *position, u8 { u8 objectEventId; const u8 *script; - - objectEventId = GetObjectEventIdByPosition(position->x, position->y, position->elevation); + s16 currX = gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x; + s16 currY = gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y; + u8 currBehavior = MapGridGetMetatileBehaviorAt(currX, currY); + + switch (direction) + { + case DIR_EAST: + if (MetatileBehavior_IsSidewaysStairsLeftSideAny(metatileBehavior)) + // sideways stairs left-side to your right -> check northeast + objectEventId = GetObjectEventIdByPosition(currX + 1, currY - 1, position->elevation); + else if (MetatileBehavior_IsSidewaysStairsRightSideAny(currBehavior)) + // on top of right-side stairs -> check southeast + objectEventId = GetObjectEventIdByPosition(currX + 1, currY + 1, position->elevation); + else + // check in front of player + objectEventId = GetObjectEventIdByPosition(position->x, position->y, position->elevation); + break; + case DIR_WEST: + if (MetatileBehavior_IsSidewaysStairsRightSideAny(metatileBehavior)) + // facing sideways stairs right side -> check northwest + objectEventId = GetObjectEventIdByPosition(currX - 1, currY - 1, position->elevation); + else if (MetatileBehavior_IsSidewaysStairsLeftSideAny(currBehavior)) + // on top of left-side stairs -> check southwest + objectEventId = GetObjectEventIdByPosition(currX - 1, currY + 1, position->elevation); + else + // check in front of player + objectEventId = GetObjectEventIdByPosition(position->x, position->y, position->elevation); + break; + default: + objectEventId = GetObjectEventIdByPosition(position->x, position->y, position->elevation); + break; + } + if (objectEventId == OBJECT_EVENTS_COUNT || gObjectEvents[objectEventId].localId == OBJ_EVENT_ID_PLAYER) { if (MetatileBehavior_IsCounter(metatileBehavior) != TRUE) diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c index 82532881f2..42000c5673 100644 --- a/src/field_player_avatar.c +++ b/src/field_player_avatar.c @@ -92,6 +92,8 @@ static bool8 PlayerAnimIsMultiFrameStationaryAndStateNotTurning(void); static bool8 PlayerIsAnimActive(void); static bool8 PlayerCheckIfAnimFinishedOrInactive(void); +static void PlayerWalkSlow(u8 direction); +static void PlayerRunSlow(u8 direction); static void PlayerRun(u8); static void PlayerNotOnBikeCollide(u8); static void PlayerNotOnBikeCollideWithFarawayIslandMew(u8); @@ -456,7 +458,22 @@ static bool8 ForcedMovement_None(void) static bool8 DoForcedMovement(u8 direction, void (*moveFunc)(u8)) { struct PlayerAvatar *playerAvatar = &gPlayerAvatar; - u8 collision = CheckForPlayerAvatarCollision(direction); + u8 collision; + + // Check for sideways stairs onto ice movement. + switch (direction) + { + case DIR_NORTHWEST: + case DIR_SOUTHWEST: + direction = DIR_WEST; + break; + case DIR_NORTHEAST: + case DIR_SOUTHEAST: + direction = DIR_EAST; + break; + } + + collision = CheckForPlayerAvatarCollision(direction); playerAvatar->flags |= PLAYER_AVATAR_FLAG_FORCED_MOVE; if (collision) @@ -621,7 +638,7 @@ static void PlayerNotOnBikeTurningInPlace(u8 direction, u16 heldKeys) static void PlayerNotOnBikeMoving(u8 direction, u16 heldKeys) { u8 collision = CheckForPlayerAvatarCollision(direction); - + if (collision) { if (collision == COLLISION_LEDGE_JUMP) @@ -642,7 +659,7 @@ static void PlayerNotOnBikeMoving(u8 direction, u16 heldKeys) return; } } - + if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) { // same speed as running @@ -653,13 +670,20 @@ static void PlayerNotOnBikeMoving(u8 direction, u16 heldKeys) if (!(gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_UNDERWATER) && (heldKeys & B_BUTTON) && FlagGet(FLAG_SYS_B_DASH) && IsRunningDisallowed(gObjectEvents[gPlayerAvatar.objectEventId].currentMetatileBehavior) == 0) { - PlayerRun(direction); + if (ObjectMovingOnRockStairs(&gObjectEvents[gPlayerAvatar.objectEventId], direction)) + PlayerRunSlow(direction); + else + PlayerRun(direction); + gPlayerAvatar.flags |= PLAYER_AVATAR_FLAG_DASH; return; } else { - PlayerWalkNormal(direction); + if (ObjectMovingOnRockStairs(&gObjectEvents[gPlayerAvatar.objectEventId], direction)) + PlayerWalkSlow(direction); + else + PlayerWalkNormal(direction); } } @@ -670,6 +694,7 @@ static u8 CheckForPlayerAvatarCollision(u8 direction) x = playerObjEvent->currentCoords.x; y = playerObjEvent->currentCoords.y; + MoveCoords(direction, &x, &y); return CheckForObjectEventCollision(playerObjEvent, x, y, direction, MapGridGetMetatileBehaviorAt(x, y)); } @@ -688,6 +713,8 @@ static u8 CheckForPlayerAvatarStaticCollision(u8 direction) u8 CheckForObjectEventCollision(struct ObjectEvent *objectEvent, s16 x, s16 y, u8 direction, u8 metatileBehavior) { u8 collision = GetCollisionAtCoords(objectEvent, x, y, direction); + u8 currentBehavior = MapGridGetMetatileBehaviorAt(objectEvent->currentCoords.x, objectEvent->currentCoords.y); + if (collision == COLLISION_ELEVATION_MISMATCH && CanStopSurfing(x, y, direction)) return COLLISION_STOP_SURFING; @@ -705,6 +732,22 @@ u8 CheckForObjectEventCollision(struct ObjectEvent *objectEvent, s16 x, s16 y, u return COLLISION_ROTATING_GATE; CheckAcroBikeCollision(x, y, metatileBehavior, &collision); } + + //sideways stairs logic + /* + if (MetatileBehavior_IsSidewaysStairsLeftSideTop(metatileBehavior) && direction == DIR_EAST) + return COLLISION_IMPASSABLE; //moving onto left-side top edge east from ground -> cannot move + else if (MetatileBehavior_IsSidewaysStairsRightSideTop(metatileBehavior) && direction == DIR_WEST) + return COLLISION_IMPASSABLE; //moving onto left-side top edge east from ground -> cannot move + else if (MetatileBehavior_IsSidewaysStairsRightSideBottom(metatileBehavior) && (direction == DIR_EAST || direction == DIR_SOUTH)) + return COLLISION_IMPASSABLE; + else if (MetatileBehavior_IsSidewaysStairsLeftSideBottom(metatileBehavior) && (direction == DIR_WEST || direction == DIR_SOUTH)) + return COLLISION_IMPASSABLE; + else if ((MetatileBehavior_IsSidewaysStairsLeftSideTop(currentBehavior) || MetatileBehavior_IsSidewaysStairsRightSideTop(currentBehavior)) + && direction == DIR_NORTH && collision == COLLISION_NONE) + return COLLISION_IMPASSABLE; //trying to move north off of top-most tile onto same level doesn't work + */ + return collision; } @@ -967,6 +1010,17 @@ void PlayerSetAnimId(u8 movementActionId, u8 copyableMovement) } } +// slow +static void PlayerWalkSlow(u8 direction) +{ + PlayerSetAnimId(GetWalkSlowMovementAction(direction), 2); +} +static void PlayerRunSlow(u8 direction) +{ + PlayerSetAnimId(GetPlayerRunSlowMovementAction(direction), 2); +} + +// normal speed (1 speed) void PlayerWalkNormal(u8 direction) { PlayerSetAnimId(GetWalkNormalMovementAction(direction), COPY_MOVE_WALK); @@ -1628,7 +1682,7 @@ static void CreateStopSurfingTask(u8 direction) LockPlayerFieldControls(); Overworld_ClearSavedMusic(); Overworld_ChangeMusicToDefault(); - gPlayerAvatar.flags &= ~PLAYER_AVATAR_FLAG_SURFING; + gPlayerAvatar.flags ^= PLAYER_AVATAR_FLAG_SURFING; gPlayerAvatar.flags |= PLAYER_AVATAR_FLAG_ON_FOOT; gPlayerAvatar.preventStep = TRUE; taskId = CreateTask(Task_StopSurfingInit, 0xFF); @@ -2422,3 +2476,71 @@ static u8 TrySpinPlayerForWarp(struct ObjectEvent *object, s16 *delayTimer) *delayTimer = 0; return sSpinDirections[object->facingDirection]; } + +//sideways stairs +u8 GetRightSideStairsDirection(u8 direction) +{ + switch (direction) + { + case DIR_WEST: + return DIR_NORTHWEST; + case DIR_EAST: + return DIR_SOUTHEAST; + default: + if (direction > DIR_EAST) + direction -= DIR_EAST; + + return direction; + } +} + +u8 GetLeftSideStairsDirection(u8 direction) +{ + switch (direction) + { + case DIR_WEST: + return DIR_SOUTHWEST; + case DIR_EAST: + return DIR_NORTHEAST; + default: + if (direction > DIR_EAST) + direction -= DIR_EAST; + + return direction; + } +} + +bool8 ObjectMovingOnRockStairs(struct ObjectEvent *objectEvent, u8 direction) +{ + #if SLOW_MOVEMENT_ON_STAIRS == TRUE + s16 x = objectEvent->currentCoords.x; + s16 y = objectEvent->currentCoords.y; + + // TODO followers on sideways stairs + if (IsFollowerVisible() && (objectEvent->isPlayer || objectEvent->localId == OBJ_EVENT_ID_FOLLOWER)) + return FALSE; + + switch (direction) + { + case DIR_NORTH: + return MetatileBehavior_IsRockStairs(MapGridGetMetatileBehaviorAt(x,y)); + case DIR_SOUTH: + MoveCoords(DIR_SOUTH, &x, &y); + return MetatileBehavior_IsRockStairs(MapGridGetMetatileBehaviorAt(x,y)); + case DIR_WEST: + case DIR_EAST: + case DIR_NORTHEAST: + case DIR_NORTHWEST: + case DIR_SOUTHWEST: + case DIR_SOUTHEAST: + // directionOverwrite is only used for sideways stairs motion + if (objectEvent->directionOverwrite) + return TRUE; + default: + return FALSE; + } + #else + return FALSE; + #endif +} + diff --git a/src/metatile_behavior.c b/src/metatile_behavior.c index 924428aea4..6de81c0f05 100644 --- a/src/metatile_behavior.c +++ b/src/metatile_behavior.c @@ -66,8 +66,13 @@ static const u8 sTileBitAttributes[NUM_METATILE_BEHAVIORS] = [MB_SLIDE_NORTH] = TILE_FLAG_UNUSED, [MB_SLIDE_SOUTH] = TILE_FLAG_UNUSED, [MB_TRICK_HOUSE_PUZZLE_8_FLOOR] = TILE_FLAG_UNUSED, - [MB_UNUSED_49] = TILE_FLAG_UNUSED, - [MB_UNUSED_4A] = TILE_FLAG_UNUSED, + [MB_SIDEWAYS_STAIRS_RIGHT_SIDE] = TILE_FLAG_UNUSED, + [MB_SIDEWAYS_STAIRS_LEFT_SIDE] = TILE_FLAG_UNUSED, + [MB_SIDEWAYS_STAIRS_RIGHT_SIDE_TOP] = TILE_FLAG_UNUSED, + [MB_SIDEWAYS_STAIRS_LEFT_SIDE_TOP] = TILE_FLAG_UNUSED, + [MB_SIDEWAYS_STAIRS_RIGHT_SIDE_BOTTOM] = TILE_FLAG_UNUSED, + [MB_SIDEWAYS_STAIRS_LEFT_SIDE_BOTTOM] = TILE_FLAG_UNUSED, + [MB_ROCK_STAIRS] = TILE_FLAG_UNUSED, [MB_EASTWARD_CURRENT] = TILE_FLAG_UNUSED | TILE_FLAG_SURFABLE, [MB_WESTWARD_CURRENT] = TILE_FLAG_UNUSED | TILE_FLAG_SURFABLE, [MB_NORTHWARD_CURRENT] = TILE_FLAG_UNUSED | TILE_FLAG_SURFABLE, @@ -1400,3 +1405,81 @@ bool8 MetatileBehavior_IsTrainerHillTimer(u8 metatileBehavior) else return FALSE; } + +bool8 MetatileBehavior_IsSidewaysStairsRightSide(u8 metatileBehavior) +{ + if (metatileBehavior == MB_SIDEWAYS_STAIRS_RIGHT_SIDE || metatileBehavior == MB_SIDEWAYS_STAIRS_RIGHT_SIDE_BOTTOM) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSidewaysStairsLeftSide(u8 metatileBehavior) +{ + if (metatileBehavior == MB_SIDEWAYS_STAIRS_LEFT_SIDE || metatileBehavior == MB_SIDEWAYS_STAIRS_LEFT_SIDE_BOTTOM) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSidewaysStairsRightSideTop(u8 metatileBehavior) +{ + if (metatileBehavior == MB_SIDEWAYS_STAIRS_RIGHT_SIDE_TOP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSidewaysStairsLeftSideTop(u8 metatileBehavior) +{ + if (metatileBehavior == MB_SIDEWAYS_STAIRS_LEFT_SIDE_TOP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSidewaysStairsRightSideBottom(u8 metatileBehavior) +{ + if (metatileBehavior == MB_SIDEWAYS_STAIRS_RIGHT_SIDE_BOTTOM) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSidewaysStairsLeftSideBottom(u8 metatileBehavior) +{ + if (metatileBehavior == MB_SIDEWAYS_STAIRS_LEFT_SIDE_BOTTOM) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSidewaysStairsRightSideAny(u8 metatileBehavior) +{ + if (metatileBehavior == MB_SIDEWAYS_STAIRS_RIGHT_SIDE + || metatileBehavior == MB_SIDEWAYS_STAIRS_RIGHT_SIDE_BOTTOM + || metatileBehavior == MB_SIDEWAYS_STAIRS_RIGHT_SIDE_TOP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsSidewaysStairsLeftSideAny(u8 metatileBehavior) +{ + if (metatileBehavior == MB_SIDEWAYS_STAIRS_LEFT_SIDE + || metatileBehavior == MB_SIDEWAYS_STAIRS_LEFT_SIDE_BOTTOM + || metatileBehavior == MB_SIDEWAYS_STAIRS_LEFT_SIDE_TOP) + return TRUE; + else + return FALSE; +} + +bool8 MetatileBehavior_IsRockStairs(u8 metatileBehavior) +{ + if (metatileBehavior == MB_ROCK_STAIRS) + return TRUE; + else + return FALSE; +} + + diff --git a/src/scrcmd.c b/src/scrcmd.c index b642f41ede..80a91133e3 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -1008,6 +1008,8 @@ bool8 ScrCmd_applymovement(struct ScriptContext *ctx) ClearObjectEventMovement(objEvent, &gSprites[objEvent->spriteId]); gSprites[objEvent->spriteId].animCmdIndex = 0; // Reset start frame of animation } + + gObjectEvents[GetObjectEventIdByLocalId(localId)].directionOverwrite = DIR_NONE; ScriptMovement_StartObjectMovementScript(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, movementScript); sMovingNpcId = localId; objEvent = GetFollowerObject(); @@ -1032,6 +1034,7 @@ bool8 ScrCmd_applymovementat(struct ScriptContext *ctx) u8 mapGroup = ScriptReadByte(ctx); u8 mapNum = ScriptReadByte(ctx); + gObjectEvents[GetObjectEventIdByLocalId(localId)].directionOverwrite = DIR_NONE; ScriptMovement_StartObjectMovementScript(localId, mapNum, mapGroup, movementScript); sMovingNpcId = localId; return FALSE;