Merge remote-tracking branch 'merrp/followers-expanded-id' into merrp-merge
This commit is contained in:
commit
7426a98dc5
@ -2440,3 +2440,10 @@
|
||||
.2byte \dest
|
||||
.endm
|
||||
|
||||
@ hide any follower pokemon if present,
|
||||
@ putting them into their pokeball;
|
||||
@ by default waits for their movement to finish
|
||||
.macro hidefollower wait=1
|
||||
callnative ScrFunc_hidefollower
|
||||
.2byte \wait
|
||||
.endm
|
||||
|
||||
@ -118,7 +118,6 @@ EventScript_FollowerSwap:
|
||||
return
|
||||
|
||||
EventScript_FollowerMoveNorth:
|
||||
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_WalkUp
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Movement_WalkDown
|
||||
waitmovement 0
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Common_Movement_FaceUp
|
||||
@ -126,7 +125,6 @@ EventScript_FollowerMoveNorth:
|
||||
return
|
||||
|
||||
EventScript_FollowerMoveEast:
|
||||
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_WalkRight
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Movement_WalkLeft
|
||||
waitmovement 0
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Common_Movement_FaceRight
|
||||
@ -134,7 +132,6 @@ EventScript_FollowerMoveEast:
|
||||
return
|
||||
|
||||
EventScript_FollowerMoveSouth:
|
||||
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_WalkDown
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Movement_WalkUp
|
||||
waitmovement 0
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Common_Movement_FaceDown
|
||||
@ -142,7 +139,6 @@ EventScript_FollowerMoveSouth:
|
||||
return
|
||||
|
||||
EventScript_FollowerMoveWest:
|
||||
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_WalkLeft
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Movement_WalkRight
|
||||
waitmovement 0
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Common_Movement_FaceLeft
|
||||
|
||||
@ -33,7 +33,8 @@ EventScript_PkmnCenterNurse_IllTakeYourPkmn2::
|
||||
return
|
||||
|
||||
EventScript_PkmnCenterNurse_TakeAndHealPkmn::
|
||||
applymovement VAR_0x800B, Movement_PkmnCenterNurse_Turn @ Changed from Common_Movement_WalkInPlaceFasterLeft to force the follower to enter their Poké Ball
|
||||
hidefollower 0
|
||||
applymovement VAR_0x800B, Movement_PkmnCenterNurse_Turn
|
||||
waitmovement 0
|
||||
dofieldeffect FLDEFF_POKECENTER_HEAL
|
||||
.if OW_UNION_DISABLE_CHECK == FALSE && OW_FLAG_MOVE_UNION_ROOM_CHECK != 0
|
||||
|
||||
@ -8,11 +8,13 @@ Std_MsgboxNPC:
|
||||
return
|
||||
|
||||
Std_MsgboxSign:
|
||||
setflag FLAG_SAFE_FOLLOWER_MOVEMENT
|
||||
lockall
|
||||
message NULL
|
||||
waitmessage
|
||||
waitbuttonpress
|
||||
releaseall
|
||||
clearflag FLAG_SAFE_FOLLOWER_MOVEMENT
|
||||
return
|
||||
|
||||
Std_MsgboxDefault:
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
// 16x32, 32x32, 64x64 etc are fine
|
||||
#define OW_MON_WANDER_WALK TRUE // If true, OW pokemon with MOVEMENT_TYPE_WANDER will walk-in-place in between steps.
|
||||
// Follower Pokémon
|
||||
#define OW_FOLLOWERS_ENABLED FALSE // Enables follower Pokémon, HGSS style. Requires OW_POKEMON_OBJECT_EVENTS. Note that additional scripting may be required for them to be fully supported!
|
||||
#define OW_FOLLOWERS_ENABLED TRUE // Enables follower Pokémon, HGSS style. Requires OW_POKEMON_OBJECT_EVENTS. Note that additional scripting may be required for them to be fully supported!
|
||||
#define OW_FOLLOWERS_BOBBING TRUE // If true, follower pokemon will bob up and down during their idle & walking animations
|
||||
#define OW_FOLLOWERS_POKEBALLS TRUE // Followers will emerge from the pokeball they are stored in, instead of a normal pokeball
|
||||
|
||||
|
||||
@ -295,6 +295,47 @@
|
||||
|
||||
#define SHADOW_SIZE_XL_BATTLE_ONLY SHADOW_SIZE_NONE // Battle-only definition for XL shadow size.
|
||||
|
||||
// If true, adds a small amount of overhead
|
||||
// to OW code so that large (48x48, 64x64) OWs
|
||||
// will display correctly under bridges, etc.
|
||||
#define LARGE_OW_SUPPORT TRUE
|
||||
|
||||
// See global.h for the toggle of OW_GFX_COMPRESS
|
||||
// Compressed gfx are incompatible with non-power-of-two sprite sizes:
|
||||
// (You should not use 48x48 sprites/tables for compressed gfx)
|
||||
// 16x32, 32x32, 64x64 etc are fine
|
||||
|
||||
// Followers will emerge from the pokeball they are stored in,
|
||||
// instead of a normal pokeball
|
||||
#define OW_MON_POKEBALLS TRUE
|
||||
|
||||
// New/old handling for followers during scripts;
|
||||
// TRUE: Script collisions hide follower, FLAG_SAFE_FOLLOWER_MOVEMENT on by default
|
||||
// (scripted player movement moves follower too!)
|
||||
// FALSE: Script collisions unhandled, FLAG_SAFE_FOLLOWER_MOVEMENT off by default
|
||||
#define OW_MON_SCRIPT_MOVEMENT TRUE
|
||||
|
||||
// If set, the only pokemon allowed to follow you
|
||||
// will be those matching species, met location,
|
||||
// and/or met level;
|
||||
// These accept vars, too: VAR_TEMP_1, etc
|
||||
#define OW_MON_ALLOWED_SPECIES (0)
|
||||
#define OW_MON_ALLOWED_MET_LVL (0)
|
||||
#define OW_MON_ALLOWED_MET_LOC (0)
|
||||
// Examples:
|
||||
// Yellow Pikachu:
|
||||
// #define OW_MON_ALLOWED_SPECIES (SPECIES_PIKACHU)
|
||||
// #define OW_MON_ALLOWED_MET_LVL (0)
|
||||
// #define OW_MON_ALLOWED_MET_LOC (MAPSEC_PALLET_TOWN)
|
||||
// Hoenn Starter:
|
||||
// #define OW_MON_ALLOWED_SPECIES (0)
|
||||
// #define OW_MON_ALLOWED_MET_LVL (5)
|
||||
// #define OW_MON_ALLOWED_MET_LOC (MAPSEC_ROUTE_101)
|
||||
// Species set in VAR_XXXX:
|
||||
// #define OW_MON_ALLOWED_SPECIES (VAR_XXXX)
|
||||
// #define OW_MON_ALLOWED_MET_LVL (0)
|
||||
// #define OW_MON_ALLOWED_MET_LOC (0)
|
||||
|
||||
#define F_INANIMATE (1 << 6)
|
||||
#define F_DISABLE_REFLECTION_PALETTE_LOAD (1 << 7)
|
||||
|
||||
|
||||
@ -1647,7 +1647,9 @@
|
||||
#define FLAG_ENABLE_MULTI_CORRIDOR_DOOR (SPECIAL_FLAGS_START + 0x2)
|
||||
#define FLAG_SPECIAL_FLAG_UNUSED_0x4003 (SPECIAL_FLAGS_START + 0x3) // Unused Flag
|
||||
#define FLAG_STORING_ITEMS_IN_PYRAMID_BAG (SPECIAL_FLAGS_START + 0x4)
|
||||
#define FLAG_SAFE_FOLLOWER_MOVEMENT (SPECIAL_FLAGS_START + 0x5) // When set, applymovement does not put the follower inside a pokeball
|
||||
// When set, `applymovement` does not hide follower pokemon;
|
||||
// Also, scripted movements on the player will move follower(s), too
|
||||
#define FLAG_SAFE_FOLLOWER_MOVEMENT (SPECIAL_FLAGS_START + 0x5)
|
||||
// FLAG_SPECIAL_FLAG_0x4005 - 0x407F also exist and are unused
|
||||
#define SPECIAL_FLAGS_END (SPECIAL_FLAGS_START + 0x7F)
|
||||
#define NUM_SPECIAL_FLAGS (SPECIAL_FLAGS_END - SPECIAL_FLAGS_START + 1)
|
||||
|
||||
@ -177,6 +177,7 @@ u8 GetWalkInPlaceFastMovementAction(u32);
|
||||
u8 GetWalkInPlaceNormalMovementAction(u32);
|
||||
u8 GetWalkInPlaceSlowMovementAction(u32);
|
||||
u8 GetCollisionAtCoords(struct ObjectEvent *, s16 x, s16 y, u32 dir);
|
||||
u32 GetObjectObjectCollidesWith(struct ObjectEvent *objectEvent, s16 x, s16 y, bool32 addCoords);
|
||||
void MoveCoords(u8 direction, s16 *x, s16 *y);
|
||||
bool8 ObjectEventIsHeldMovementActive(struct ObjectEvent *);
|
||||
u8 ObjectEventClearHeldMovementIfFinished(struct ObjectEvent *);
|
||||
|
||||
@ -381,7 +381,7 @@ static const bool8 sMovementTypeHasRange[NUM_MOVEMENT_TYPES] = {
|
||||
[MOVEMENT_TYPE_COPY_PLAYER_CLOCKWISE_IN_GRASS] = TRUE,
|
||||
};
|
||||
|
||||
const u8 gInitialMovementTypeFacingDirections[] = {
|
||||
const u8 gInitialMovementTypeFacingDirections[NUM_MOVEMENT_TYPES] = {
|
||||
[MOVEMENT_TYPE_NONE] = DIR_SOUTH,
|
||||
[MOVEMENT_TYPE_LOOK_AROUND] = DIR_SOUTH,
|
||||
[MOVEMENT_TYPE_WANDER_AROUND] = DIR_SOUTH,
|
||||
@ -463,6 +463,7 @@ const u8 gInitialMovementTypeFacingDirections[] = {
|
||||
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_UP] = DIR_NORTH,
|
||||
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_LEFT] = DIR_WEST,
|
||||
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_RIGHT] = DIR_EAST,
|
||||
[MOVEMENT_TYPE_FOLLOW_PLAYER] = DIR_SOUTH,
|
||||
};
|
||||
|
||||
#include "data/object_events/object_event_graphics_info_pointers.h"
|
||||
@ -1925,6 +1926,14 @@ struct Pokemon *GetFirstLiveMon(void)
|
||||
u32 i;
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
struct Pokemon *mon = &gPlayerParty[i];
|
||||
if ((OW_MON_ALLOWED_SPECIES && GetMonData(mon, MON_DATA_SPECIES_OR_EGG) != VarGet(OW_MON_ALLOWED_SPECIES))
|
||||
|| (OW_MON_ALLOWED_MET_LVL && GetMonData(mon, MON_DATA_MET_LEVEL) != VarGet(OW_MON_ALLOWED_MET_LVL))
|
||||
|| (OW_MON_ALLOWED_MET_LOC && GetMonData(mon, MON_DATA_MET_LOCATION) != VarGet(OW_MON_ALLOWED_MET_LOC)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gPlayerParty[i].hp > 0 && !(gPlayerParty[i].box.isEgg || gPlayerParty[i].box.isBadEgg))
|
||||
return &gPlayerParty[i];
|
||||
}
|
||||
@ -2083,8 +2092,9 @@ static void RefreshFollowerGraphics(struct ObjectEvent *objEvent)
|
||||
sprite->y += -(graphicsInfo->height >> 1) - sprite->centerToCornerVecY;
|
||||
}
|
||||
|
||||
if (OW_GFX_COMPRESS)
|
||||
LoadSheetGraphicsInfo(graphicsInfo, objEvent->graphicsId, sprite);
|
||||
#if OW_GFX_COMPRESS
|
||||
LoadSheetGraphicsInfo(graphicsInfo, objEvent->graphicsId, sprite);
|
||||
#endif
|
||||
|
||||
sprite->oam.shape = graphicsInfo->oam->shape;
|
||||
sprite->oam.size = graphicsInfo->oam->size;
|
||||
@ -5409,6 +5419,7 @@ bool8 MovementType_FollowPlayer_Moving(struct ObjectEvent *objectEvent, struct S
|
||||
objectEvent->movementActionId = MOVEMENT_ACTION_NONE;
|
||||
sprite->sActionFuncId = 0;
|
||||
objectEvent->singleMovementActive = FALSE;
|
||||
objectEvent->facingDirectionLocked = FALSE;
|
||||
if (sprite->sTypeFuncId) // restore nonzero state
|
||||
sprite->sTypeFuncId = 1;
|
||||
}
|
||||
@ -5479,7 +5490,8 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
|
||||
{
|
||||
// Animate exiting pokeball
|
||||
// Player is jumping, but follower is invisible
|
||||
if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2)
|
||||
// don't emerge if player is jumping or moving via script
|
||||
if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2 || ArePlayerFieldControlsLocked())
|
||||
{
|
||||
sprite->sTypeFuncId = 0; // return to shadowing state
|
||||
return FALSE;
|
||||
@ -5500,6 +5512,15 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
|
||||
|
||||
// Follow player
|
||||
direction = GetDirectionToFace(x, y, targetX, targetY);
|
||||
// During a script, if player sidesteps or backsteps,
|
||||
// mirror player's direction instead
|
||||
if (ArePlayerFieldControlsLocked()
|
||||
&& gObjectEvents[gPlayerAvatar.objectEventId].facingDirection != gObjectEvents[gPlayerAvatar.objectEventId].movementDirection
|
||||
) {
|
||||
direction = gObjectEvents[gPlayerAvatar.objectEventId].movementDirection;
|
||||
objectEvent->facingDirectionLocked = TRUE;
|
||||
}
|
||||
|
||||
MoveCoords(direction, &x, &y);
|
||||
GetCollisionAtCoords(objectEvent, x, y, direction); // Sets directionOverwrite for stairs
|
||||
if (GetLedgeJumpDirection(x, y, direction) != DIR_NONE)
|
||||
@ -5507,53 +5528,28 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
|
||||
// InitJumpRegular will set the proper speed
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetJump2MovementAction(direction));
|
||||
}
|
||||
else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH))
|
||||
else if (playerAction >= MOVEMENT_ACTION_WALK_SLOW_DOWN && playerAction <= MOVEMENT_ACTION_WALK_SLOW_RIGHT)
|
||||
{
|
||||
// Set follow speed according to player's speed
|
||||
if (playerAction >= MOVEMENT_ACTION_RUN_DOWN_SLOW && playerAction <= MOVEMENT_ACTION_RUN_RIGHT_SLOW)
|
||||
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) // on sideways stairs
|
||||
objectEvent->movementActionId = GetWalkNormalMovementAction(direction);
|
||||
else
|
||||
objectEvent->movementActionId = GetWalkFastMovementAction(direction);
|
||||
}
|
||||
else if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2)
|
||||
{
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(direction));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (playerAction >= MOVEMENT_ACTION_WALK_SLOW_DOWN && playerAction <= MOVEMENT_ACTION_WALK_SLOW_RIGHT)
|
||||
{
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(direction));
|
||||
}
|
||||
else
|
||||
{
|
||||
objectEvent->movementActionId = GetWalkNormalMovementAction(direction);
|
||||
if (OW_FOLLOWERS_BOBBING == TRUE)
|
||||
sprite->y2 = -1;
|
||||
}
|
||||
}
|
||||
sprite->sActionFuncId = 0;
|
||||
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 if (gSprites[gPlayerAvatar.spriteId].data[4] == MOVE_SPEED_FAST_1)
|
||||
{
|
||||
objectEvent->movementActionId = GetWalkFastMovementAction(direction);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkNormalMovementAction(direction));
|
||||
objectEvent->movementActionId = GetWalkNormalMovementAction(direction);
|
||||
if (OW_FOLLOWERS_BOBBING == TRUE)
|
||||
sprite->y2 = -1;
|
||||
}
|
||||
sprite->sActionFuncId = 0;
|
||||
objectEvent->singleMovementActive = TRUE;
|
||||
sprite->sTypeFuncId = 2;
|
||||
return TRUE;
|
||||
@ -6206,13 +6202,17 @@ static bool8 IsMetatileDirectionallyImpassable(struct ObjectEvent *objectEvent,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool8 DoesObjectCollideWithObjectAt(struct ObjectEvent *objectEvent, s16 x, s16 y)
|
||||
{
|
||||
u32 GetObjectObjectCollidesWith(struct ObjectEvent *objectEvent, s16 x, s16 y, bool32 addCoords) {
|
||||
u8 i;
|
||||
struct ObjectEvent *curObject;
|
||||
|
||||
if (objectEvent->localId == OBJ_EVENT_ID_FOLLOWER)
|
||||
return FALSE; // follower cannot collide with other objects, but they can collide with it
|
||||
return OBJECT_EVENTS_COUNT; // follower cannot collide with other objects, but they can collide with it
|
||||
|
||||
if (addCoords) {
|
||||
x += objectEvent->currentCoords.x;
|
||||
y += objectEvent->currentCoords.y;
|
||||
}
|
||||
|
||||
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
|
||||
{
|
||||
@ -6223,11 +6223,16 @@ static bool8 DoesObjectCollideWithObjectAt(struct ObjectEvent *objectEvent, s16
|
||||
if ((curObject->currentCoords.x == x && curObject->currentCoords.y == y) || (curObject->previousCoords.x == x && curObject->previousCoords.y == y))
|
||||
{
|
||||
if (AreElevationsCompatible(objectEvent->currentElevation, curObject->currentElevation))
|
||||
return TRUE;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
return OBJECT_EVENTS_COUNT;
|
||||
}
|
||||
|
||||
static bool8 DoesObjectCollideWithObjectAt(struct ObjectEvent *objectEvent, s16 x, s16 y)
|
||||
{
|
||||
return (GetObjectObjectCollidesWith(objectEvent, x, y, FALSE) < OBJECT_EVENTS_COUNT);
|
||||
}
|
||||
|
||||
bool8 IsBerryTreeSparkling(u8 localId, u8 mapNum, u8 mapGroup)
|
||||
@ -6379,6 +6384,19 @@ static u8 TryUpdateMovementActionOnStairs(struct ObjectEvent *objectEvent, u8 mo
|
||||
}
|
||||
}
|
||||
|
||||
static const u8 sActionIdToCopyableMovement[] = {
|
||||
[MOVEMENT_ACTION_FACE_DOWN ... MOVEMENT_ACTION_FACE_RIGHT] = COPY_MOVE_FACE,
|
||||
[MOVEMENT_ACTION_WALK_SLOW_DOWN ... MOVEMENT_ACTION_WALK_NORMAL_RIGHT] = COPY_MOVE_WALK,
|
||||
[MOVEMENT_ACTION_JUMP_2_DOWN ... MOVEMENT_ACTION_JUMP_2_RIGHT] = COPY_MOVE_JUMP2,
|
||||
[MOVEMENT_ACTION_WALK_FAST_DOWN ... MOVEMENT_ACTION_WALK_FAST_RIGHT] = COPY_MOVE_WALK,
|
||||
[MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN ... MOVEMENT_ACTION_PLAYER_RUN_RIGHT] = COPY_MOVE_WALK,
|
||||
// Not a typo; follower needs to take an action with a duration == JUMP's,
|
||||
// and JUMP2 here will lead to WALK_SLOW later
|
||||
[MOVEMENT_ACTION_JUMP_DOWN ... MOVEMENT_ACTION_JUMP_RIGHT] = COPY_MOVE_JUMP2,
|
||||
|
||||
[MOVEMENT_ACTION_NONE] = COPY_MOVE_NONE,
|
||||
};
|
||||
|
||||
bool8 ObjectEventSetHeldMovement(struct ObjectEvent *objectEvent, u8 movementActionId)
|
||||
{
|
||||
if (ObjectEventIsMovementOverridden(objectEvent))
|
||||
@ -6391,6 +6409,16 @@ bool8 ObjectEventSetHeldMovement(struct ObjectEvent *objectEvent, u8 movementAct
|
||||
objectEvent->heldMovementActive = TRUE;
|
||||
objectEvent->heldMovementFinished = FALSE;
|
||||
gSprites[objectEvent->spriteId].sActionFuncId = 0;
|
||||
|
||||
// When player is moved via script, set copyable movement
|
||||
// for any followers via a lookup table
|
||||
if (ArePlayerFieldControlsLocked() &&
|
||||
objectEvent->isPlayer &&
|
||||
FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT))
|
||||
{
|
||||
objectEvent->playerCopyableMovement = sActionIdToCopyableMovement[objectEvent->movementActionId];
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -6414,6 +6442,15 @@ void ObjectEventClearHeldMovement(struct ObjectEvent *objectEvent)
|
||||
objectEvent->heldMovementFinished = FALSE;
|
||||
gSprites[objectEvent->spriteId].sTypeFuncId = 0;
|
||||
gSprites[objectEvent->spriteId].sActionFuncId = 0;
|
||||
|
||||
// When player is moved via script, set copyable movement
|
||||
// for any followers via a lookup table
|
||||
if (ArePlayerFieldControlsLocked() &&
|
||||
objectEvent->isPlayer &&
|
||||
FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT))
|
||||
{
|
||||
objectEvent->playerCopyableMovement = sActionIdToCopyableMovement[objectEvent->movementActionId];
|
||||
}
|
||||
}
|
||||
|
||||
u8 ObjectEventCheckHeldMovementStatus(struct ObjectEvent *objectEvent)
|
||||
|
||||
51
src/scrcmd.c
51
src/scrcmd.c
@ -998,6 +998,20 @@ bool8 ScrCmd_fadeinbgm(struct ScriptContext *ctx)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct ObjectEvent * ScriptHideFollower(void) {
|
||||
struct ObjectEvent *obj = GetFollowerObject();
|
||||
|
||||
if (obj == NULL || obj->invisible)
|
||||
return NULL;
|
||||
|
||||
ClearObjectEventMovement(obj, &gSprites[obj->spriteId]);
|
||||
gSprites[obj->spriteId].animCmdIndex = 0; // Reset start frame of animation
|
||||
// Note: ScriptMovement_ returns TRUE on error
|
||||
if (ScriptMovement_StartObjectMovementScript(obj->localId, obj->mapGroup, obj->mapNum, EnterPokeballMovement))
|
||||
return NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool8 ScrCmd_applymovement(struct ScriptContext *ctx)
|
||||
{
|
||||
u16 localId = VarGet(ScriptReadHalfword(ctx));
|
||||
@ -1015,17 +1029,11 @@ bool8 ScrCmd_applymovement(struct ScriptContext *ctx)
|
||||
gObjectEvents[GetObjectEventIdByLocalId(localId)].directionOverwrite = DIR_NONE;
|
||||
ScriptMovement_StartObjectMovementScript(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, movementScript);
|
||||
sMovingNpcId = localId;
|
||||
objEvent = GetFollowerObject();
|
||||
// Force follower into pokeball
|
||||
if (localId != OBJ_EVENT_ID_FOLLOWER
|
||||
&& !FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT)
|
||||
&& (movementScript < Common_Movement_FollowerSafeStart || movementScript > Common_Movement_FollowerSafeEnd)
|
||||
&& (objEvent = GetFollowerObject())
|
||||
&& !objEvent->invisible)
|
||||
if (localId != OBJ_EVENT_ID_FOLLOWER &&
|
||||
!FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT)
|
||||
&& (movementScript < Common_Movement_FollowerSafeStart || movementScript > Common_Movement_FollowerSafeEnd))
|
||||
{
|
||||
ClearObjectEventMovement(objEvent, &gSprites[objEvent->spriteId]);
|
||||
gSprites[objEvent->spriteId].animCmdIndex = 0; // Reset start frame of animation
|
||||
ScriptMovement_StartObjectMovementScript(OBJ_EVENT_ID_FOLLOWER, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, EnterPokeballMovement);
|
||||
ScriptHideFollower();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@ -1247,8 +1255,11 @@ bool8 ScrCmd_lockall(struct ScriptContext *ctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ObjectEvent *followerObj = GetFollowerObject();
|
||||
FreezeObjects_WaitForPlayer();
|
||||
SetupNativeScript(ctx, IsFreezePlayerFinished);
|
||||
if (FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT) && followerObj) // Unfreeze follower object (conditionally)
|
||||
UnfreezeObjectEvent(followerObj);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -2550,3 +2561,23 @@ bool8 Scrcmd_getobjectfacingdirection(struct ScriptContext *ctx)
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool8 ScrFunc_hidefollower(struct ScriptContext *ctx) {
|
||||
bool16 wait = VarGet(ScriptReadHalfword(ctx));
|
||||
struct ObjectEvent *obj;
|
||||
|
||||
if ((obj = ScriptHideFollower()) != NULL && wait) {
|
||||
sMovingNpcId = obj->localId;
|
||||
sMovingNpcMapGroup = obj->mapGroup;
|
||||
sMovingNpcMapNum = obj->mapNum;
|
||||
SetupNativeScript(ctx, WaitForMovementFinish);
|
||||
}
|
||||
|
||||
// Just in case, prevent `applymovement`
|
||||
// from hiding the follower again
|
||||
if (obj)
|
||||
FlagSet(FLAG_SAFE_FOLLOWER_MOVEMENT);
|
||||
|
||||
// execute next script command with no delay
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "mystery_gift.h"
|
||||
#include "util.h"
|
||||
#include "constants/event_objects.h"
|
||||
#include "constants/flags.h"
|
||||
#include "constants/map_scripts.h"
|
||||
#include "field_message_box.h"
|
||||
|
||||
@ -255,6 +256,8 @@ void ScriptContext_SetupScript(const u8 *ptr)
|
||||
InitScriptContext(&sGlobalScriptContext, gScriptCmdTable, gScriptCmdTableEnd);
|
||||
SetupBytecodeScript(&sGlobalScriptContext, ptr);
|
||||
LockPlayerFieldControls();
|
||||
if (OW_MON_SCRIPT_MOVEMENT)
|
||||
FlagSet(FLAG_SAFE_FOLLOWER_MOVEMENT);
|
||||
sGlobalScriptContextStatus = CONTEXT_RUNNING;
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "global.h"
|
||||
#include "script_movement.h"
|
||||
#include "event_object_movement.h"
|
||||
#include "event_scripts.h"
|
||||
#include "task.h"
|
||||
#include "util.h"
|
||||
#include "constants/event_objects.h"
|
||||
@ -205,13 +206,34 @@ static void ScriptMovement_MoveObjects(u8 taskId)
|
||||
}
|
||||
}
|
||||
|
||||
// from event_object_movement
|
||||
#define sTypeFuncId data[1]
|
||||
#define sTimer data[5]
|
||||
|
||||
static void ScriptMovement_TakeStep(u8 taskId, u8 moveScrId, u8 objEventId, const u8 *movementScript)
|
||||
{
|
||||
u8 nextMoveActionId;
|
||||
struct ObjectEvent *obj = &gObjectEvents[objEventId];
|
||||
|
||||
if (ObjectEventIsHeldMovementActive(&gObjectEvents[objEventId])
|
||||
&& !ObjectEventClearHeldMovementIfFinished(&gObjectEvents[objEventId]))
|
||||
if (ObjectEventIsHeldMovementActive(obj) &&
|
||||
!ObjectEventClearHeldMovementIfFinished(obj))
|
||||
{
|
||||
// If, while undergoing scripted movement,
|
||||
// a non-player object collides with an active follower pokemon,
|
||||
// put that follower into a pokeball
|
||||
// (sTimer helps limit this expensive check to once per step)
|
||||
if (OW_MON_SCRIPT_MOVEMENT &&
|
||||
gSprites[obj->spriteId].sTimer == 1 &&
|
||||
(objEventId = GetObjectObjectCollidesWith(obj, 0, 0, TRUE)) < OBJECT_EVENTS_COUNT &&
|
||||
// switch `obj` to follower
|
||||
((obj = &gObjectEvents[objEventId])->movementType == MOVEMENT_TYPE_FOLLOW_PLAYER) &&
|
||||
gSprites[obj->spriteId].sTypeFuncId != 0)
|
||||
{
|
||||
ClearObjectEventMovement(obj, &gSprites[obj->spriteId]);
|
||||
ScriptMovement_StartObjectMovementScript(obj->localId, obj->mapNum, obj->mapGroup, EnterPokeballMovement);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nextMoveActionId = *movementScript;
|
||||
if (nextMoveActionId == MOVEMENT_ACTION_STEP_END)
|
||||
@ -229,3 +251,5 @@ static void ScriptMovement_TakeStep(u8 taskId, u8 moveScrId, u8 objEventId, cons
|
||||
}
|
||||
}
|
||||
|
||||
#undef sTypeFuncId
|
||||
#undef sTimer
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user