diff --git a/include/follower_npc.h b/include/follower_npc.h index 52355a78b7..abfbf0962a 100644 --- a/include/follower_npc.h +++ b/include/follower_npc.h @@ -20,6 +20,7 @@ enum FollowerNPCDataTypes FNPC_DATA_WARP_END, FNPC_DATA_SURF_BLOB, FNPC_DATA_COME_OUT_DOOR, + FNPC_DATA_FORCED_MOVEMENT, FNPC_DATA_OBJ_ID, FNPC_DATA_CURRENT_SPRITE, FNPC_DATA_DELAYED_STATE, @@ -62,7 +63,8 @@ enum FollowerNPCSurfBlobStates FNPC_SURF_BLOB_DESTROY }; -enum FollowerNPCOutOfDoorTaskStates{ +enum FollowerNPCOutOfDoorTaskStates +{ OPEN_DOOR, NPC_WALK_OUT, CLOSE_DOOR, @@ -70,7 +72,8 @@ enum FollowerNPCOutOfDoorTaskStates{ REALLOW_MOVEMENT }; -enum FollowerNPCHandleEscalatorFinishTaskStates{ +enum FollowerNPCHandleEscalatorFinishTaskStates +{ MOVE_TO_PLAYER_POS, WAIT_FOR_PLAYER_MOVE, SHOW_FOLLOWER_DOWN, diff --git a/include/global.h b/include/global.h index f4c944b64f..27c0a85e15 100644 --- a/include/global.h +++ b/include/global.h @@ -219,7 +219,8 @@ struct NPCFollower u8 inProgress:1; u8 warpEnd:1; u8 createSurfBlob:3; - u8 comeOutDoorStairs:3; + u8 comeOutDoorStairs:2; + u8 forcedMovement:1; u8 objId; u8 currentSprite; u8 delayedState; diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c index d02ecbd9fc..55542a3588 100644 --- a/src/field_player_avatar.c +++ b/src/field_player_avatar.c @@ -382,8 +382,16 @@ void PlayerStep(u8 direction, u16 newKeys, u16 heldKeys) DoPlayerAvatarTransition(); if (TryDoMetatileBehaviorForcedMovement() == 0) { - MovePlayerAvatarUsingKeypadInput(direction, newKeys, heldKeys); - PlayerAllowForcedMovementIfMovingSameDirection(); + if (GetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT) != FALSE) + { + gPlayerAvatar.preventStep = TRUE; + CreateTask(Task_MoveNPCFollowerAfterForcedMovement, 1); + } + else + { + MovePlayerAvatarUsingKeypadInput(direction, newKeys, heldKeys); + PlayerAllowForcedMovementIfMovingSameDirection(); + } } } } @@ -510,7 +518,11 @@ static bool8 DoForcedMovement(u8 direction, void (*moveFunc)(u8)) else { if (collision == COLLISION_LEDGE_JUMP) + { + SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, FALSE); PlayerJumpLedge(direction); + } + playerAvatar->flags |= PLAYER_AVATAR_FLAG_FORCED_MOVE; playerAvatar->runningState = MOVING; return TRUE; @@ -518,12 +530,11 @@ static bool8 DoForcedMovement(u8 direction, void (*moveFunc)(u8)) } else { + if (PlayerHasFollowerNPC()) + SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, TRUE); + playerAvatar->runningState = MOVING; moveFunc(direction); - if (PlayerHasFollowerNPC() - && gObjectEvents[GetFollowerNPCObjectId()].invisible == FALSE - && FindTaskIdByFunc(Task_MoveNPCFollowerAfterForcedMovement) == TASK_NONE) - CreateTask(Task_MoveNPCFollowerAfterForcedMovement, 3); return TRUE; } } diff --git a/src/follower_npc.c b/src/follower_npc.c index d9882b61bf..fcfe60dda8 100644 --- a/src/follower_npc.c +++ b/src/follower_npc.c @@ -83,6 +83,9 @@ void SetFollowerNPCData(enum FollowerNPCDataTypes type, u32 value) case FNPC_DATA_COME_OUT_DOOR: gSaveBlock3Ptr->NPCfollower.comeOutDoorStairs = value; break; + case FNPC_DATA_FORCED_MOVEMENT: + gSaveBlock3Ptr->NPCfollower.forcedMovement = value; + break; case FNPC_DATA_OBJ_ID: gSaveBlock3Ptr->NPCfollower.objId = value; break; @@ -155,6 +158,8 @@ u32 GetFollowerNPCData(enum FollowerNPCDataTypes type) return gSaveBlock3Ptr->NPCfollower.createSurfBlob; case FNPC_DATA_COME_OUT_DOOR: return gSaveBlock3Ptr->NPCfollower.comeOutDoorStairs; + case FNPC_DATA_FORCED_MOVEMENT: + return gSaveBlock3Ptr->NPCfollower.forcedMovement; case FNPC_DATA_OBJ_ID: return gSaveBlock3Ptr->NPCfollower.objId; case FNPC_DATA_CURRENT_SPRITE: @@ -720,9 +725,7 @@ u32 DetermineFollowerNPCState(struct ObjectEvent *follower, u32 state, u32 direc MoveCoords(direction, &followerX, &followerY); nextBehavior = MapGridGetMetatileBehaviorAt(followerX, followerY); - - if (FindTaskIdByFunc(Task_MoveNPCFollowerAfterForcedMovement) == TASK_NONE) - follower->facingDirectionLocked = FALSE; + follower->facingDirectionLocked = FALSE; // Follower won't do delayed movement until player does a movement. if (!IsStateMovement(state) && delayedState) @@ -777,10 +780,6 @@ u32 DetermineFollowerNPCState(struct ObjectEvent *follower, u32 state, u32 direc RETURN_STATE(MOVEMENT_ACTION_WALK_NORMAL_DOWN, direction); case MOVEMENT_ACTION_WALK_FAST_DOWN ... MOVEMENT_ACTION_WALK_FAST_RIGHT: - // Handle player on waterfall. - if (PlayerIsUnderWaterfall(&gObjectEvents[gPlayerAvatar.objectEventId]) && (state == MOVEMENT_ACTION_WALK_FAST_UP)) - return MOVEMENT_INVALID; - // Handle ice tile (some walking animation). if (MetatileBehavior_IsIce(follower->currentMetatileBehavior) || MetatileBehavior_IsTrickHouseSlipperyFloor(follower->currentMetatileBehavior)) follower->disableAnim = TRUE; @@ -789,6 +788,9 @@ u32 DetermineFollowerNPCState(struct ObjectEvent *follower, u32 state, u32 direc if (GetFollowerNPCData(FNPC_DATA_CURRENT_SPRITE) == FOLLOWER_NPC_SPRITE_INDEX_SURF && GetFollowerNPCSprite() == GetFollowerNPCData(FNPC_DATA_GFX_ID)) RETURN_STATE(MOVEMENT_ACTION_SURF_STILL_DOWN, direction); + if (MetatileBehavior_IsMuddySlope(follower->currentMetatileBehavior)) + follower->facingDirectionLocked = TRUE; + RETURN_STATE(MOVEMENT_ACTION_WALK_FAST_DOWN, direction); case MOVEMENT_ACTION_WALK_FASTER_DOWN ... MOVEMENT_ACTION_WALK_FASTER_RIGHT: @@ -798,10 +800,6 @@ u32 DetermineFollowerNPCState(struct ObjectEvent *follower, u32 state, u32 direc RETURN_STATE(MOVEMENT_ACTION_WALK_FASTER_DOWN, direction); case MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN ... MOVEMENT_ACTION_RIDE_WATER_CURRENT_RIGHT: - // Handle player on waterfall. - if (PlayerIsUnderWaterfall(&gObjectEvents[gPlayerAvatar.objectEventId]) && IsPlayerSurfingNorth()) - return MOVEMENT_INVALID; - RETURN_STATE(MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN, direction); // Acro bike. @@ -1544,37 +1542,20 @@ void FollowerNPC_TryRemoveFollowerOnWhiteOut(void) #undef tDoorY // Task data -#define PREVENT_PLAYER_STEP 0 -#define DO_ALL_FORCED_MOVEMENTS 1 -#define NPC_INTO_PLAYER 2 -#define ENABLE_PLAYER_STEP 3 +#define NPC_INTO_PLAYER 0 +#define ENABLE_PLAYER_STEP 1 void Task_MoveNPCFollowerAfterForcedMovement(u8 taskId) { struct ObjectEvent *follower = &gObjectEvents[GetFollowerNPCObjectId()]; struct ObjectEvent *player = &gObjectEvents[gPlayerAvatar.objectEventId]; - // Prevent player input until all forced mmovements are done and the follower is hidden. - if (gTasks[taskId].tState == PREVENT_PLAYER_STEP) + // The NPC will take an extra step and be on the same tile as the player. + if (gTasks[taskId].tState == NPC_INTO_PLAYER && ObjectEventClearHeldMovementIfFinished(player) != 0 && ObjectEventClearHeldMovementIfFinished(follower) != 0) { - gPlayerAvatar.preventStep = TRUE; - gTasks[taskId].tState = DO_ALL_FORCED_MOVEMENTS; - } - // The player will keep doing forced movments until they land on a non-forced-move metatile or hit collision. - else if (gTasks[taskId].tState == DO_ALL_FORCED_MOVEMENTS && ObjectEventClearHeldMovementIfFinished(player) != 0) - { - // Lock follower facing direction for muddy slope. if (follower->currentMetatileBehavior == MB_MUDDY_SLOPE) follower->facingDirectionLocked = TRUE; - if (TryDoMetatileBehaviorForcedMovement() == 0) - gTasks[taskId].tState = NPC_INTO_PLAYER; - - return; - } - // The NPC will take an extra step and be on the same tile as the player. - else if (gTasks[taskId].tState == NPC_INTO_PLAYER && ObjectEventClearHeldMovementIfFinished(player) != 0 && ObjectEventClearHeldMovementIfFinished(follower) != 0) - { ObjectEventSetHeldMovement(follower, GetWalkFastMovementAction(DetermineFollowerNPCDirection(player, follower))); gTasks[taskId].tState = ENABLE_PLAYER_STEP; return; @@ -1585,14 +1566,13 @@ void Task_MoveNPCFollowerAfterForcedMovement(u8 taskId) follower->facingDirectionLocked = FALSE; HideNPCFollower(); SetFollowerNPCData(FNPC_DATA_WARP_END, FNPC_WARP_REAPPEAR); + SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, FALSE); gPlayerAvatar.preventStep = FALSE; DestroyTask(taskId); } } #undef tState -#undef PREVENT_PLAYER_STEP -#undef DO_ALL_FORCED_MOVEMENTS #undef NPC_INTO_PLAYER #undef ENABLE_PLAYER_STEP @@ -1628,7 +1608,6 @@ void ScriptDestroyFollowerNPC(struct ScriptContext *ctx) return; RemoveObjectEvent(&gObjectEvents[GetFollowerNPCData(FNPC_DATA_OBJ_ID)]); - FlagSet(GetFollowerNPCData(FNPC_DATA_EVENT_FLAG)); ClearFollowerNPCData(); UpdateFollowingPokemon(); }