diff --git a/data/scripts/field_move_scripts.inc b/data/scripts/field_move_scripts.inc index a9ba2355c7..ead669c6b2 100644 --- a/data/scripts/field_move_scripts.inc +++ b/data/scripts/field_move_scripts.inc @@ -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 diff --git a/src/event_object_movement.c b/src/event_object_movement.c index 59b669869b..f29f7c10ea 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -5492,6 +5492,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; diff --git a/src/fldeff_rocksmash.c b/src/fldeff_rocksmash.c index 27689b02e3..71044aa30a 100644 --- a/src/fldeff_rocksmash.c +++ b/src/fldeff_rocksmash.c @@ -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; } diff --git a/src/scrcmd.c b/src/scrcmd.c index b15c3d18a8..c7d881e216 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -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) @@ -1004,7 +1003,11 @@ 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