Added option to speed up follower interactions

By setting the FAST_FOLLOWERS define to TRUE, you can now:
- Have the follower exit a door faster, avoiding the need to stop and wait for the follower to exit.
- Have the follower jump down ledges faster, avoiding the need to stop and wait for the follower to land.
This commit is contained in:
W1serV1ser committed 2023-03-29 20:58:14 -07:00
1 parent 872d06ce9a
commit 2dbeffa92b
9 files changed
+231 -11

No files matched your search

@@ -103,7 +103,7 @@
"trainer_type": "TRAINER_TYPE_NONE",
"trainer_sight_or_berry_tree_id": "0",
"script": "NULL",
"flag": "FLAG_UNUSED_0x020"
"flag": "FLAG_FOLLOWER_ACTIVE"
}
],
"warp_events": [
@@ -29,7 +29,7 @@ LittlerootTown_ProfessorBirchsLab_MapScripts::
LittlerootTown_ProfessorBirchsLab_OnTransition:
call Common_EventScript_SetupRivalGfxId
call ProfBirch_EventScript_UpdateLocation
setflag FLAG_UNUSED_0x020
setflag FLAG_FOLLOWER_ACTIVE
goto_if_ge VAR_DEX_UPGRADE_JOHTO_STARTER_STATE, 6, LittlerootTown_ProfessorBirchsLab_EventScript_SetAfterJohtoStarterLayout
goto_if_ge VAR_DEX_UPGRADE_JOHTO_STARTER_STATE, 4, LittlerootTown_ProfessorBirchsLab_EventScript_SetJohtoStarterLayout
goto_if_eq VAR_DEX_UPGRADE_JOHTO_STARTER_STATE, 3, LittlerootTown_ProfessorBirchsLab_EventScript_CheckReadyForJohtoStarter
+3 -2
View File
@@ -41,8 +41,9 @@
#define FLAG_TEMP_1F (TEMP_FLAGS_START + 0x1F)
#define TEMP_FLAGS_END FLAG_TEMP_1F
#define FLAG_UNUSED_0x020 0x20 // Unused Flag
#define FLAG_UNUSED_0x021 0x21 // Unused Flag
#define FLAG_FOLLOWER_ACTIVE 0x20 // Reveals the follower object
#define FLAG_FOLLOWER_IN_BUILDING 0x21 // Used for speeding up follower door exiting
#define FLAG_UNUSED_0x022 0x22 // Unused Flag
#define FLAG_UNUSED_0x023 0x23 // Unused Flag
#define FLAG_UNUSED_0x024 0x24 // Unused Flag
+2
View File
@@ -155,4 +155,6 @@
#define SIDEWAYS_STAIRS_IMPLEMENTED FALSE
#define POST_BATTLE_FOLLOWER_FIX FALSE
#define FAST_FOLLOWERS FALSE
#endif // GUARD_CONSTANTS_GLOBAL_H
@@ -734,11 +734,15 @@ static const s16 sJumpInitDisplacements[] = {
[JUMP_DISTANCE_IN_PLACE] = 0,
[JUMP_DISTANCE_NORMAL] = 1,
[JUMP_DISTANCE_FAR] = 1,
[JUMP_DISTANCE_FAR_QUICK] = 1,
[JUMP_DISTANCE_FAR_QUICKER] = 1,
};
static const s16 sJumpDisplacements[] = {
[JUMP_DISTANCE_IN_PLACE] = 0,
[JUMP_DISTANCE_NORMAL] = 0,
[JUMP_DISTANCE_FAR] = 1,
[JUMP_DISTANCE_FAR_QUICK] = 1,
[JUMP_DISTANCE_FAR_QUICKER] = 1,
};
u8 (*const gMovementActionFuncs_Jump2Down[])(struct ObjectEvent *, struct Sprite *) = {
+126 -5
View File
@@ -49,6 +49,8 @@ enum {
JUMP_DISTANCE_IN_PLACE,
JUMP_DISTANCE_NORMAL,
JUMP_DISTANCE_FAR,
JUMP_DISTANCE_FAR_QUICK,
JUMP_DISTANCE_FAR_QUICKER,
};
// Sprite data used throughout
@@ -5728,7 +5730,19 @@ bool8 MovementAction_WalkSlowDiagonalDownRight_Step1(struct ObjectEvent *objectE
bool8 MovementAction_WalkSlowDown_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
InitWalkSlow(objectEvent, sprite, DIR_SOUTH);
if(gSaveBlock2Ptr->follower.inProgress && objectEvent == &gObjectEvents[gSaveBlock2Ptr->follower.objId])
{
if(sprite->data[7] != 19)
{
sprite->data[7] = 19;
sprite->animNum = 4;
sprite->x2 = 0;
SeekSpriteAnim(sprite, ++sprite->animCmdIndex);
}
InitWalkSlow(objectEvent, sprite, DIR_SOUTH);
}
else
InitWalkSlow(objectEvent, sprite, DIR_SOUTH);
return MovementAction_WalkSlowDown_Step1(objectEvent, sprite);
}
@@ -5744,7 +5758,19 @@ bool8 MovementAction_WalkSlowDown_Step1(struct ObjectEvent *objectEvent, struct
bool8 MovementAction_WalkSlowUp_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
InitWalkSlow(objectEvent, sprite, DIR_NORTH);
if(gSaveBlock2Ptr->follower.inProgress && objectEvent == &gObjectEvents[gSaveBlock2Ptr->follower.objId])
{
if(sprite->data[7] != 20)
{
sprite->data[7] = 20;
sprite->animNum = 5;
sprite->x2 = 0;
SeekSpriteAnim(sprite, ++sprite->animCmdIndex);
}
InitWalkSlow(objectEvent, sprite, DIR_NORTH);
}
else
InitWalkSlow(objectEvent, sprite, DIR_NORTH);
return MovementAction_WalkSlowUp_Step1(objectEvent, sprite);
}
@@ -5760,7 +5786,19 @@ 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(gSaveBlock2Ptr->follower.inProgress && objectEvent == &gObjectEvents[gSaveBlock2Ptr->follower.objId])
{
if(sprite->data[7] != 21)
{
sprite->data[7] = 21;
sprite->animNum = 6;
sprite->x2 = 8;
SeekSpriteAnim(sprite, ++sprite->animCmdIndex);
}
InitWalkSlow(objectEvent, sprite, DIR_WEST);
}
else
InitWalkSlow(objectEvent, sprite, DIR_WEST);
return MovementAction_WalkSlowLeft_Step1(objectEvent, sprite);
}
@@ -5776,7 +5814,19 @@ bool8 MovementAction_WalkSlowLeft_Step1(struct ObjectEvent *objectEvent, struct
bool8 MovementAction_WalkSlowRight_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
InitWalkSlow(objectEvent, sprite, DIR_EAST);
if(gSaveBlock2Ptr->follower.inProgress && objectEvent == &gObjectEvents[gSaveBlock2Ptr->follower.objId])
{
if(sprite->data[7] != 22)
{
sprite->data[7] = 22;
sprite->animNum = 7;
sprite->x2 = -8;
SeekSpriteAnim(sprite, ++sprite->animCmdIndex);
}
InitWalkSlow(objectEvent, sprite, DIR_EAST);
}
else
InitWalkSlow(objectEvent, sprite, DIR_EAST);
return MovementAction_WalkSlowRight_Step1(objectEvent, sprite);
}
@@ -5973,6 +6023,9 @@ enum {
JUMP_TYPE_HIGH,
JUMP_TYPE_LOW,
JUMP_TYPE_NORMAL,
#if FAST_FOLLOWERS == TRUE
JUMP_TYPE_QUICK,
#endif
};
static void InitJump(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8 direction, u8 distance, u8 type)
@@ -6080,8 +6133,18 @@ bool8 MovementAction_Jump2Down_Step0(struct ObjectEvent *objectEvent, struct Spr
{
sprite->x2 = 0;
sprite->data[7] = 10;
#if FAST_FOLLOWERS == TRUE
if(TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH))
InitJumpRegular(objectEvent, sprite, DIR_SOUTH, JUMP_DISTANCE_FAR_QUICKER, JUMP_TYPE_QUICK);
else
InitJumpRegular(objectEvent, sprite, DIR_SOUTH, JUMP_DISTANCE_FAR_QUICK, JUMP_TYPE_QUICK);
}
else
InitJumpRegular(objectEvent, sprite, DIR_SOUTH, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH);
#else
}
InitJumpRegular(objectEvent, sprite, DIR_SOUTH, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH);
#endif
return MovementAction_Jump2Down_Step1(objectEvent, sprite);
}
@@ -6102,8 +6165,18 @@ bool8 MovementAction_Jump2Up_Step0(struct ObjectEvent *objectEvent, struct Sprit
{
sprite->x2 = 0;
sprite->data[7] = 10;
#if FAST_FOLLOWERS == TRUE
if(TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH))
InitJumpRegular(objectEvent, sprite, DIR_NORTH, JUMP_DISTANCE_FAR_QUICKER, JUMP_TYPE_QUICK);
else
InitJumpRegular(objectEvent, sprite, DIR_NORTH, JUMP_DISTANCE_FAR_QUICK, JUMP_TYPE_QUICK);
}
else
InitJumpRegular(objectEvent, sprite, DIR_NORTH, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH);
#else
}
InitJumpRegular(objectEvent, sprite, DIR_NORTH, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH);
#endif
return MovementAction_Jump2Up_Step1(objectEvent, sprite);
}
@@ -6124,8 +6197,18 @@ bool8 MovementAction_Jump2Left_Step0(struct ObjectEvent *objectEvent, struct Spr
{
sprite->x2 = 8;
sprite->data[7] = 10;
#if FAST_FOLLOWERS == TRUE
if(TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH))
InitJumpRegular(objectEvent, sprite, DIR_WEST, JUMP_DISTANCE_FAR_QUICKER, JUMP_TYPE_QUICK);
else
InitJumpRegular(objectEvent, sprite, DIR_WEST, JUMP_DISTANCE_FAR_QUICK, JUMP_TYPE_QUICK);
}
else
InitJumpRegular(objectEvent, sprite, DIR_WEST, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH);
#else
}
InitJumpRegular(objectEvent, sprite, DIR_WEST, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH);
#endif
return MovementAction_Jump2Left_Step1(objectEvent, sprite);
}
@@ -6146,8 +6229,18 @@ bool8 MovementAction_Jump2Right_Step0(struct ObjectEvent *objectEvent, struct Sp
{
sprite->x2 = -8;
sprite->data[7] = 10;
#if FAST_FOLLOWERS == TRUE
if(TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH))
InitJumpRegular(objectEvent, sprite, DIR_EAST, JUMP_DISTANCE_FAR_QUICKER, JUMP_TYPE_QUICK);
else
InitJumpRegular(objectEvent, sprite, DIR_EAST, JUMP_DISTANCE_FAR_QUICK, JUMP_TYPE_QUICK);
}
else
InitJumpRegular(objectEvent, sprite, DIR_EAST, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH);
#else
}
InitJumpRegular(objectEvent, sprite, DIR_EAST, JUMP_DISTANCE_FAR, JUMP_TYPE_HIGH);
#endif
return MovementAction_Jump2Right_Step1(objectEvent, sprite);
}
@@ -9215,10 +9308,19 @@ static const s8 sJumpY_Normal[] = {
-9, -8, -6, -5, -3, -2, 0, 0
};
#if FAST_FOLLOWERS == TRUE
static const s8 sJumpY_Quick[] = {
-2, -4, -6, -8, -6, -4, -2, 0, 0
};
#endif
static const s8 *const sJumpYTable[] = {
[JUMP_TYPE_HIGH] = sJumpY_High,
[JUMP_TYPE_LOW] = sJumpY_Low,
[JUMP_TYPE_NORMAL] = sJumpY_Normal
[JUMP_TYPE_NORMAL] = sJumpY_Normal,
#if FAST_FOLLOWERS == TRUE
[JUMP_TYPE_QUICK] = sJumpY_Quick,
#endif
};
static s16 GetJumpY(s16 i, u8 type)
@@ -9244,16 +9346,35 @@ static u8 DoJumpSpriteMovement(struct Sprite *sprite)
[JUMP_DISTANCE_IN_PLACE] = 16,
[JUMP_DISTANCE_NORMAL] = 16,
[JUMP_DISTANCE_FAR] = 32,
#if FAST_FOLLOWERS == TRUE
[JUMP_DISTANCE_FAR_QUICK] = 16,
[JUMP_DISTANCE_FAR_QUICKER] = 8,
#endif
};
u8 distanceToShift[] = {
[JUMP_DISTANCE_IN_PLACE] = 0,
[JUMP_DISTANCE_NORMAL] = 0,
[JUMP_DISTANCE_FAR] = 1,
#if FAST_FOLLOWERS == TRUE
[JUMP_DISTANCE_FAR_QUICK] = 1,
[JUMP_DISTANCE_FAR_QUICKER] = 0,
#endif
};
u8 result = 0;
if (sprite->sDistance != JUMP_DISTANCE_IN_PLACE)
#if FAST_FOLLOWERS == TRUE
{
if (sprite->sDistance == JUMP_DISTANCE_FAR_QUICKER)
Step4(sprite, sprite->sDirection);
else if (sprite->sDistance == JUMP_DISTANCE_FAR_QUICK)
Step2(sprite, sprite->sDirection);
else
Step1(sprite, sprite->sDirection);
}
#else
Step1(sprite, sprite->sDirection);
#endif
sprite->y2 = GetJumpY(sprite->sTimer >> distanceToShift[sprite->sDistance], sprite->sJumpType);
+28
View File
@@ -1,8 +1,10 @@
#include "global.h"
#include "decompress.h"
#include "event_data.h"
#include "event_object_movement.h"
#include "field_camera.h"
#include "field_control_avatar.h"
#include "field_door.h"
#include "field_effect.h"
#include "field_effect_helpers.h"
#include "field_player_avatar.h"
@@ -1371,6 +1373,18 @@ static void Task_UseFly(u8 taskId)
FieldEffectStart(FLDEFF_USE_FLY);
#if FAST_FOLLOWERS == TRUE
if (FlagGet(FLAG_FOLLOWER_IN_BUILDING))
{
// In case the player just exited a building and the follower has not exited the building
FlagClear(FLAG_FOLLOWER_IN_BUILDING);
gSaveBlock2Ptr->follower.comeOutDoorStairs = 0;
gSaveBlock2Ptr->follower.warpEnd = 0;
FieldAnimateDoorClose(gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x, gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y - 1);
}
else
FollowerIntoPokeball();
#else
if (gSaveBlock2Ptr->follower.inProgress)
{
// In case the player just exited a building and the follower has not exited the building
@@ -1379,6 +1393,7 @@ static void Task_UseFly(u8 taskId)
FollowerIntoPokeball();
}
#endif
task->data[0]++;
}
@@ -3065,6 +3080,18 @@ static void SurfFieldEffect_FieldMovePose(struct Task *task)
ObjectEventSetHeldMovement(objectEvent, MOVEMENT_ACTION_START_ANIM_IN_DIRECTION);
task->tState++;
#if FAST_FOLLOWERS == TRUE
if (FlagGet(FLAG_FOLLOWER_IN_BUILDING))
{
// in case the follower hasn't left a warp yet
FlagClear(FLAG_FOLLOWER_IN_BUILDING);
gSaveBlock2Ptr->follower.comeOutDoorStairs = 0;
gSaveBlock2Ptr->follower.warpEnd = 0;
FieldAnimateDoorClose(gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x, gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y - 1);
}
else
FollowerIntoPokeball();
#else
if (gSaveBlock2Ptr->follower.inProgress)
{
// in case the follower hasn't left a warp yet
@@ -3073,6 +3100,7 @@ static void SurfFieldEffect_FieldMovePose(struct Task *task)
FollowerIntoPokeball();
}
#endif
}
}
+16 -1
View File
@@ -344,14 +344,23 @@ static void Task_ExitDoor(u8 taskId)
if (IsPlayerStandingStill())
{
u8 objEventId;
task->data[1] = FieldAnimateDoorClose(*x, *y);
#if FAST_FOLLOWERS == TRUE
if (!gSaveBlock2Ptr->follower.inProgress)
#endif
task->data[1] = FieldAnimateDoorClose(*x, *y);
objEventId = GetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_PLAYER, 0, 0);
ObjectEventClearHeldMovementIfFinished(&gObjectEvents[objEventId]);
task->tState = 3;
}
break;
case 3:
#if FAST_FOLLOWERS == TRUE
if (gSaveBlock2Ptr->follower.inProgress || task->data[1] < 0 || gTasks[task->data[1]].isActive != TRUE)
#else
if (task->data[1] < 0 || gTasks[task->data[1]].isActive != TRUE)
#endif
{
FollowMe_SetIndicatorToComeOutDoor();
FollowMe_WarpSetEnd();
@@ -362,6 +371,12 @@ static void Task_ExitDoor(u8 taskId)
case 4:
UnlockPlayerFieldControls();
DestroyTask(taskId);
#if FAST_FOLLOWERS == TRUE
if (gSaveBlock2Ptr->follower.inProgress)
FlagSet(FLAG_FOLLOWER_IN_BUILDING);
#endif
break;
}
}
+50 -1
View File
@@ -249,6 +249,18 @@ void FollowMe(struct ObjectEvent* npc, u8 state, bool8 ignoreScriptActive)
{
gSaveBlock2Ptr->follower.warpEnd = 0;
#if FAST_FOLLOWERS == TRUE
if (gSaveBlock2Ptr->follower.comeOutDoorStairs == 1 || (FlagGet(FLAG_FOLLOWER_IN_BUILDING) && gMapHeader.mapType != MAP_TYPE_INDOOR))
{
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_BIKE))
{
FlagClear(FLAG_FOLLOWER_IN_BUILDING);
gSaveBlock2Ptr->follower.comeOutDoorStairs = 0;
FieldAnimateDoorClose(player->currentCoords.x, player->currentCoords.y - 1);
}
else
{
#else
if (gSaveBlock2Ptr->follower.comeOutDoorStairs == 1)
{
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_BIKE))
@@ -256,6 +268,7 @@ void FollowMe(struct ObjectEvent* npc, u8 state, bool8 ignoreScriptActive)
else
{
gPlayerAvatar.preventStep = TRUE;
#endif
taskId = CreateTask(Task_FollowerOutOfDoor, 1);
gTasks[taskId].data[0] = 0;
gTasks[taskId].data[2] = follower->currentCoords.x;
@@ -809,12 +822,23 @@ void Task_DoDoorWarp(u8 taskId)
FreezeObjectEvents();
PlayerGetDestCoords(x, y);
PlaySE(GetDoorSoundEffect(*x, *y - 1));
task->data[1] = FieldAnimateDoorOpen(*x, *y - 1);
#if FAST_FOLLOWERS == TRUE
if (!FlagGet(FLAG_FOLLOWER_IN_BUILDING))
#endif
task->data[1] = FieldAnimateDoorOpen(*x, *y - 1);
task->data[0] = 1;
break;
case 1:
#if FAST_FOLLOWERS == TRUE
if (FlagGet(FLAG_FOLLOWER_IN_BUILDING) || task->data[1] < 0 || gTasks[task->data[1]].isActive != TRUE)
{
FlagClear(FLAG_FOLLOWER_IN_BUILDING);
#else
if (task->data[1] < 0 || gTasks[task->data[1]].isActive != TRUE)
{
#endif
ObjectEventClearHeldMovementIfActive(&gObjectEvents[playerObjId]);
ObjectEventSetHeldMovement(&gObjectEvents[playerObjId], MOVEMENT_ACTION_WALK_NORMAL_UP);
@@ -890,11 +914,35 @@ static void Task_FollowerOutOfDoor(u8 taskId)
//if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH) && ObjectEventClearHeldMovementIfFinished(player))
//SetPlayerAvatarTransitionFlags(PLAYER_AVATAR_FLAG_ON_FOOT); //Temporarily stop running
#if FAST_FOLLOWERS == FALSE
if (ObjectEventClearHeldMovementIfFinished(player))
ObjectEventTurn(player, GetPlayerFaceToDoorDirection(player, follower)); //The player should face towards the follow as the exit the door
#endif
switch (task->data[0])
{
#if FAST_FOLLOWERS == TRUE
case 0:
FlagClear(FLAG_FOLLOWER_IN_BUILDING);
FreezeObjectEvents();
task->data[0] = 1;
break;
case 1:
follower->invisible = FALSE;
ObjectEventTurn(follower, DIR_SOUTH); //The follower should be facing down when it comes out the door
follower->singleMovementActive = FALSE;
follower->heldMovementActive = FALSE;
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH))
ObjectEventSetHeldMovement(follower, MOVEMENT_ACTION_WALK_FASTER_DOWN);
else
ObjectEventSetHeldMovement(follower, MOVEMENT_ACTION_WALK_FAST_DOWN); //follower step down
task->data[0] = 2;
break;
case 2:
if (/*ObjectEventClearHeldMovementIfFinished(follower)*/follower->currentCoords.y == *y + 1)
#else
case 0:
FreezeObjectEvents();
task->data[1] = FieldAnimateDoorOpen(follower->currentCoords.x, follower->currentCoords.y);
@@ -916,6 +964,7 @@ static void Task_FollowerOutOfDoor(u8 taskId)
break;
case 2:
if (/*ObjectEventClearHeldMovementIfFinished(follower)*/follower->movementActionId == 0x9E)
#endif
{
task->data[1] = FieldAnimateDoorClose(*x, *y);
task->data[0] = 3;