Merge branch 'followers' into lighting

This commit is contained in:
Ariel A 2023-01-03 18:19:19 -05:00
commit 4bee03bc18
7 changed files with 190 additions and 42 deletions

View File

@ -11,27 +11,26 @@ EventScript_CutTree::
goto_if_eq VAR_RESULT, NO, EventScript_CancelCut
msgbox Text_MonUsedFieldMove, MSGBOX_DEFAULT
closemessage
EventScript_CutTreeCommon:
callfunc ScrFunc_IsFollowerFieldMoveUser
.2byte VAR_0x8004
setfieldeffectargument 3, VAR_0x8004 @ skip pose if so
dofieldeffect FLDEFF_USE_CUT_ON_TREE
waitstate
goto EventScript_CutTreeDown
end
@ Use cut from party menu
EventScript_UseCut::
lockall
dofieldeffect FLDEFF_USE_CUT_ON_TREE
waitstate
goto EventScript_CutTreeDown
end
EventScript_CutTreeDown::
setflag FLAG_SAFE_FOLLOWER_MOVEMENT
EventScript_CutTreeDown:: @ fallthrough
setflag FLAG_SAFE_FOLLOWER_MOVEMENT
call_if_eq VAR_0x8004, TRUE, EventScript_FollowerFieldMove
applymovement VAR_LAST_TALKED, Movement_CutTreeDown
waitmovement 0
removeobject VAR_LAST_TALKED
releaseall
end
@ Use cut from party menu
EventScript_UseCut::
lockall
goto EventScript_CutTreeCommon
Movement_CutTreeDown:
cut_tree
step_end
@ -58,6 +57,11 @@ Text_CantCut:
.string "This tree looks like it can be\n"
.string "CUT down!$"
@ Use rock smash from party menu
EventScript_UseRockSmash::
lockall
goto EventScript_RockSmashCommon
@ Interact with smashable rock
EventScript_RockSmash::
lockall
@ -71,20 +75,16 @@ EventScript_RockSmash::
goto_if_eq VAR_RESULT, NO, EventScript_CancelSmash
msgbox Text_MonUsedFieldMove, MSGBOX_DEFAULT
closemessage
EventScript_RockSmashCommon:
@ check if follower should use the field move
callfunc ScrFunc_IsFollowerFieldMoveUser
.2byte VAR_0x8004
setfieldeffectargument 3, VAR_0x8004 @ skip pose if so
dofieldeffect FLDEFF_USE_ROCK_SMASH
waitstate
goto EventScript_SmashRock
end
@ Use rock smash from party menu
EventScript_UseRockSmash::
lockall
dofieldeffect FLDEFF_USE_ROCK_SMASH
waitstate
goto EventScript_SmashRock
end
EventScript_SmashRock::
EventScript_SmashRock:: @ fallthrough
setflag FLAG_SAFE_FOLLOWER_MOVEMENT
call_if_eq VAR_0x8004, TRUE, EventScript_FollowerFieldMove
applymovement VAR_LAST_TALKED, Movement_SmashRock
waitmovement 0
removeobject VAR_LAST_TALKED
@ -96,10 +96,120 @@ EventScript_SmashRock::
releaseall
end
EventScript_FollowerFieldMove:
callfunc ScrFunc_GetDirectionToFace
.2byte VAR_0x8005
.byte OBJ_EVENT_ID_FOLLOWER
.byte OBJ_EVENT_ID_PLAYER
specialvar VAR_0x8006, GetPlayerFacingDirection
goto_if_eq VAR_0x8005, DIR_NONE, EventScript_FollowerFieldMoveEnd
@ Swap follower and player
call EventScript_FollowerSwap
@ Face follower in direction and jump
switch VAR_0x8006
case DIR_NORTH, EventScript_FollowerJumpNorth
case DIR_EAST, EventScript_FollowerJumpEast
case DIR_SOUTH, EventScript_FollowerJumpSouth
case DIR_WEST, EventScript_FollowerJumpWest
EventScript_FollowerFieldMoveEnd:
return
EventScript_FollowerSwap:
switch VAR_0x8005
case DIR_NORTH, EventScript_FollowerMoveNorth
case DIR_EAST, EventScript_FollowerMoveEast
case DIR_SOUTH, EventScript_FollowerMoveSouth
case DIR_WEST, EventScript_FollowerMoveWest
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
waitmovement 0
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
waitmovement 0
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
waitmovement 0
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
waitmovement 0
return
EventScript_FollowerJumpNorth:
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_JumpUp
waitmovement 0
return
EventScript_FollowerJumpEast:
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_JumpRight
waitmovement 0
return
EventScript_FollowerJumpSouth:
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_JumpDown
waitmovement 0
return
EventScript_FollowerJumpWest:
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_JumpLeft
waitmovement 0
return
EventScript_EndSmash::
releaseall
end
Movement_WalkUp:
walk_up
step_end
Movement_JumpUp:
jump_in_place_up
step_end
Movement_WalkRight:
walk_right
step_end
Movement_JumpRight:
jump_in_place_right
step_end
Movement_WalkDown:
walk_down
step_end
Movement_JumpDown:
jump_in_place_down
step_end
Movement_WalkLeft:
walk_left
step_end
Movement_JumpLeft:
jump_in_place_left
step_end
Movement_SmashRock:
rock_smash_break
step_end

View File

@ -441,6 +441,7 @@ bool8 CopyablePlayerMovement_Jump(struct ObjectEvent *, struct Sprite *, u8, boo
u8 MovementType_FollowPlayer_Shadow(struct ObjectEvent *, struct Sprite *);
u8 MovementType_FollowPlayer_Active(struct ObjectEvent *, struct Sprite *);
u8 MovementType_FollowPlayer_Moving(struct ObjectEvent *, struct Sprite *);
void StartSpriteAnimInDirection(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8 direction, u8 animNum);
bool8 FollowablePlayerMovement_Idle(struct ObjectEvent *, struct Sprite *, u8, bool8(u8));
bool8 FollowablePlayerMovement_FaceDirection(struct ObjectEvent *, struct Sprite *, u8, bool8(u8));

View File

@ -5123,7 +5123,6 @@ bool8 MovementType_FollowPlayer_Active(struct ObjectEvent *objectEvent, struct S
ClearObjectEventMovement(objectEvent, sprite);
ObjectEventSetSingleMovement(objectEvent, sprite, MOVEMENT_ACTION_ENTER_POKEBALL);
objectEvent->singleMovementActive = 1;
sprite->animCmdIndex = 0; // Needed for animCmdIndex weirdness
sprite->sTypeFuncId = 2; // movement action sets state to 0
return TRUE;
}
@ -5193,7 +5192,6 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
MoveObjectEventToMapCoords(objectEvent, targetX, targetY);
ObjectEventSetSingleMovement(objectEvent, sprite, MOVEMENT_ACTION_EXIT_POKEBALL);
objectEvent->singleMovementActive = 1;
sprite->animCmdIndex = 0; // Needed because of weird animCmdIndex stuff
sprite->sTypeFuncId = 2;
return TRUE;
} else if (x == targetX && y == targetY) { // don't move if already in the player's last position
@ -5634,6 +5632,41 @@ u8 GetDirectionToFace(s16 x, s16 y, s16 targetX, s16 targetY)
return DIR_SOUTH;
}
// Uses the above, but script accessible, and uses localIds
bool8 ScrFunc_GetDirectionToFace(struct ScriptContext *ctx) {
u16 *var = GetVarPointer(ScriptReadHalfword(ctx));
u8 id0 = GetObjectEventIdByLocalId(ScriptReadByte(ctx)); // source
u8 id1 = GetObjectEventIdByLocalId(ScriptReadByte(ctx)); // target
if (var == NULL)
return FALSE;
if (id0 >= OBJECT_EVENTS_COUNT || id1 >= OBJECT_EVENTS_COUNT)
*var = DIR_NONE;
else
*var = GetDirectionToFace(
gObjectEvents[id0].currentCoords.x,
gObjectEvents[id0].currentCoords.y,
gObjectEvents[id1].currentCoords.x,
gObjectEvents[id1].currentCoords.y);
return FALSE;
}
// Whether following pokemon is also the user of the field move
// Intended to be called before the field effect itself
bool8 ScrFunc_IsFollowerFieldMoveUser(struct ScriptContext *ctx) {
u16 *var = GetVarPointer(ScriptReadHalfword(ctx));
u16 userIndex = gFieldEffectArguments[0]; // field move user index
struct Pokemon *follower = GetFirstLiveMon();
struct ObjectEvent *obj = GetFollowerObject();
if (var == NULL)
return FALSE;
*var = FALSE;
if (follower && obj && !obj->invisible) {
u16 followIndex = ((u32)follower - (u32)gPlayerParty) / sizeof(struct Pokemon);
*var = userIndex == followIndex;
} else
return FALSE;
}
void SetTrainerMovementType(struct ObjectEvent *objectEvent, u8 movementType)
{
objectEvent->movementType = movementType;
@ -6761,11 +6794,13 @@ bool8 MovementAction_ExitPokeball_Step0(struct ObjectEvent *objectEvent, struct
u8 direction = gObjectEvents[gPlayerAvatar.objectEventId].facingDirection;
objectEvent->invisible = FALSE;
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) { // If player is dashing, the pokemon must come out faster
InitMoveInPlace(objectEvent, sprite, direction, GetMoveDirectionFastestAnimNum(direction) + 4, 8);
sprite->data[6] = 0; // fast speed
StartSpriteAnimInDirection(objectEvent, sprite, direction, GetMoveDirectionFastestAnimNum(direction) + 4);
sprite->data[3] = 8; // duration
sprite->data[6] = 0; // fast speed
} else {
InitMoveInPlace(objectEvent, sprite, direction, GetMoveDirectionFastestAnimNum(direction), 16);
sprite->data[6] = 1; // slow speed
StartSpriteAnimInDirection(objectEvent, sprite, direction, GetMoveDirectionFastestAnimNum(direction));
sprite->data[3] = 16; // duration
sprite->data[6] = 1; // slow speed
}
sprite->data[6] |= (direction == DIR_EAST ? 1 : 0) << 4;
ObjectEventSetGraphicsId(objectEvent, OBJ_EVENT_GFX_ANIMATED_BALL);
@ -6848,7 +6883,8 @@ bool8 MovementAction_ExitPokeball_Step1(struct ObjectEvent *objectEvent, struct
bool8 MovementAction_EnterPokeball_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite) {
u8 direction = objectEvent->facingDirection;
InitMoveInPlace(objectEvent, sprite, direction, GetMoveDirectionFasterAnimNum(direction), 16);
StartSpriteAnimInDirection(objectEvent, sprite, direction, GetMoveDirectionFasterAnimNum(direction));
sprite->data[3] = 16; // duration
sprite->data[6] = direction == DIR_EAST ? 3 : 2; // affine animation number
EndFollowerTransformEffect(objectEvent, sprite);
return MovementAction_EnterPokeball_Step1(objectEvent, sprite);

View File

@ -1569,7 +1569,6 @@ static void HideFollowerForFieldEffect(void) {
if (!followerObj || followerObj->invisible)
return;
ClearObjectEventMovement(followerObj, &gSprites[followerObj->spriteId]);
gSprites[followerObj->spriteId].animCmdIndex = 0; // Avoids a visual glitch with follower's animation frame
ObjectEventSetHeldMovement(followerObj, MOVEMENT_ACTION_ENTER_POKEBALL);
}

View File

@ -689,7 +689,6 @@ static void Task_DoDoorWarp(u8 taskId)
PlaySE(GetDoorSoundEffect(*x, *y - 1));
if (followerObject) { // Put follower into pokeball
ClearObjectEventMovement(followerObject, &gSprites[followerObject->spriteId]);
gSprites[followerObject->spriteId].animCmdIndex = 0; // Needed because of weird animCmdIndex stuff
ObjectEventSetHeldMovement(followerObject, MOVEMENT_ACTION_ENTER_POKEBALL);
}
task->data[1] = FieldAnimateDoorOpen(*x, *y - 1);

View File

@ -61,9 +61,11 @@ static void Task_DoFieldMove_Init(u8 taskId)
if (!ObjectEventIsMovementOverridden(&gObjectEvents[objEventId])
|| ObjectEventClearHeldMovementIfFinished(&gObjectEvents[objEventId]))
{
if (gMapHeader.mapType == MAP_TYPE_UNDERWATER)
if (gMapHeader.mapType == MAP_TYPE_UNDERWATER || gFieldEffectArguments[3])
{
// Skip field move pose underwater
// Skip field move pose underwater, or if arg3 is nonzero
if (gFieldEffectArguments[3])
gFieldEffectArguments[3] = 0;
FieldEffectStart(FLDEFF_FIELD_MOVE_SHOW_MON_INIT);
gTasks[taskId].func = Task_DoFieldMove_WaitForMon;
}

View File

@ -53,7 +53,6 @@
typedef u16 (*SpecialFunc)(void);
typedef void (*NativeFunc)(void);
typedef bool8 (*ScrFunc)(struct ScriptContext*);
EWRAM_DATA const u8 *gRamScriptRetAddr = NULL;
static EWRAM_DATA u32 sAddressOffset = 0; // For relative addressing in vgoto etc., used by saved scripts (e.g. Mystery Event)
@ -144,7 +143,7 @@ bool8 ScrCmd_callnative(struct ScriptContext *ctx)
bool8 ScrCmd_callfunc(struct ScriptContext *ctx)
{
u32 func = ScriptReadWord(ctx);
return ((ScrFunc) func)(ctx);
return ((ScrCmdFunc) func)(ctx);
}
bool8 ScrCmd_waitstate(struct ScriptContext *ctx)
@ -1013,17 +1012,19 @@ bool8 ScrCmd_applymovement(struct ScriptContext *ctx)
const void *movementScript = (const void *)ScriptReadWord(ctx);
struct ObjectEvent *objEvent;
// When applying script movements to follower, it may have frozen animation that must be cleared
if (localId == OBJ_EVENT_ID_FOLLOWER && (objEvent = GetFollowerObject()) && objEvent->frozen) {
ClearObjectEventMovement(objEvent, &gSprites[objEvent->spriteId]);
gSprites[objEvent->spriteId].animCmdIndex = 0; // Needed to set start frame of animation
}
ScriptMovement_StartObjectMovementScript(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, movementScript);
sMovingNpcId = localId;
if (localId != OBJ_EVENT_ID_FOLLOWER && !FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT)) { // Force follower into pokeball
objEvent = GetFollowerObject();
// return early if no follower or in shadowing state
if (objEvent == NULL || gSprites[objEvent->spriteId].data[1] == 0) {
if (objEvent == NULL || gSprites[objEvent->spriteId].data[1] == 0)
return FALSE;
}
ClearObjectEventMovement(objEvent, &gSprites[objEvent->spriteId]);
gSprites[objEvent->spriteId].animCmdIndex = 0; // Needed to set start frame of animation
ScriptMovement_StartObjectMovementScript(OBJ_EVENT_ID_FOLLOWER, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, EnterPokeballMovement);
}
return FALSE;