Add debug options for follower NPCs (#7215)
This commit is contained in:
parent
4f731835b4
commit
c6221fa50e
@ -270,6 +270,24 @@ Debug_ShowExpansionVersion::
|
||||
Debug_ExpansionVersion:
|
||||
.string "pokeemerald-expansion {STR_VAR_1}$"
|
||||
|
||||
Debug_Follower_NPC_Not_Enabled::
|
||||
msgbox Debug_Enable_To_Use_Follower_NPCs, MSGBOX_DEFAULT
|
||||
release
|
||||
end
|
||||
|
||||
Debug_Enable_To_Use_Follower_NPCs:
|
||||
.string "Feature unavailable.\nSet FNPC_ENABLE_NPC_FOLLOWERS to\lTRUE in 'include/config/follower_npc.h'.$"
|
||||
|
||||
Debug_Follower_NPC_Event_Script::
|
||||
lock
|
||||
facefollowernpc
|
||||
msgbox Debug_Follower_NPC_Test_Message, MSGBOX_DEFAULT
|
||||
releaseall
|
||||
end
|
||||
|
||||
Debug_Follower_NPC_Test_Message:
|
||||
.string "This is a Follower NPC test.$"
|
||||
|
||||
Debug_EventScript_Steven_Multi::
|
||||
call MossdeepCity_SpaceCenter_2F_EventScript_ChoosePartyForMultiBattle
|
||||
release
|
||||
|
||||
@ -82,6 +82,8 @@ const u8 *GetFollowerNPCScriptPointer(void);
|
||||
u32 GetFollowerNPCData(enum FollowerNPCDataTypes type);
|
||||
void ClearFollowerNPCData(void);
|
||||
|
||||
void CreateFollowerNPC(u32 gfx, u32 followerFlags, const u8 *scriptPtr);
|
||||
void DestroyFollowerNPC(void);
|
||||
u32 DetermineFollowerNPCState(struct ObjectEvent *follower, u32 state, u32 direction);
|
||||
void SetFollowerNPCSprite(u32 spriteIndex);
|
||||
|
||||
|
||||
108
src/debug.c
108
src/debug.c
@ -23,6 +23,7 @@
|
||||
#include "field_message_box.h"
|
||||
#include "field_screen_effect.h"
|
||||
#include "field_weather.h"
|
||||
#include "follower_npc.h"
|
||||
#include "international_string_util.h"
|
||||
#include "item.h"
|
||||
#include "item_icon.h"
|
||||
@ -58,6 +59,7 @@
|
||||
#include "constants/battle_ai.h"
|
||||
#include "constants/battle_frontier.h"
|
||||
#include "constants/coins.h"
|
||||
#include "constants/event_objects.h"
|
||||
#include "constants/expansion.h"
|
||||
#include "constants/flags.h"
|
||||
#include "constants/items.h"
|
||||
@ -71,6 +73,17 @@
|
||||
#include "fake_rtc.h"
|
||||
#include "save.h"
|
||||
|
||||
enum FollowerNPCCreateDebugMenu
|
||||
{
|
||||
DEBUG_FNPC_BRENDAN,
|
||||
DEBUG_FNPC_MAY,
|
||||
DEBUG_FNPC_STEVEN,
|
||||
DEBUG_FNPC_WALLY,
|
||||
DEBUG_FNPC_RED,
|
||||
DEBUG_FNPC_LEAF,
|
||||
DEBUG_FNPC_COUNT,
|
||||
};
|
||||
|
||||
enum FlagsVarsDebugMenu
|
||||
{
|
||||
DEBUG_FLAGVAR_MENU_ITEM_FLAGS,
|
||||
@ -223,6 +236,7 @@ static void Debug_RefreshListMenu(u8 taskId);
|
||||
static void DebugAction_OpenSubMenu(u8 taskId, const struct DebugMenuOption *items);
|
||||
static void DebugAction_OpenSubMenuFlagsVars(u8 taskId);
|
||||
static void DebugAction_OpenSubMenuFakeRTC(u8 taskId, const struct DebugMenuOption *items);
|
||||
static void DebugAction_OpenSubMenuCreateFollowerNPC(u8 taskId, const struct DebugMenuOption *items);
|
||||
static void DebugAction_ExecuteScript(u8 taskId, const u8 *script);
|
||||
|
||||
static void DebugTask_HandleMenuInput_General(u8 taskId);
|
||||
@ -241,6 +255,9 @@ static void DebugAction_Util_CheatStart(u8 taskId);
|
||||
static void DebugAction_TimeMenu_ChangeTimeOfDay(u8 taskId);
|
||||
static void DebugAction_TimeMenu_ChangeWeekdays(u8 taskId);
|
||||
|
||||
static void DebugAction_CreateFollowerNPC(u8 taskId);
|
||||
static void DebugAction_DestroyFollowerNPC(u8 taskId);
|
||||
|
||||
static void DebugAction_PCBag_Fill_PCBoxes_Fast(u8 taskId);
|
||||
static void DebugAction_PCBag_Fill_PCBoxes_Slow(u8 taskId);
|
||||
static void DebugAction_PCBag_Fill_PCItemStorage(u8 taskId);
|
||||
@ -345,6 +362,8 @@ extern const u8 Debug_CheckROMSpace[];
|
||||
extern const u8 Debug_BoxFilledMessage[];
|
||||
extern const u8 Debug_ShowExpansionVersion[];
|
||||
extern const u8 Debug_EventScript_EWRAMCounters[];
|
||||
extern const u8 Debug_Follower_NPC_Event_Script[];
|
||||
extern const u8 Debug_Follower_NPC_Not_Enabled[];
|
||||
extern const u8 Debug_EventScript_Steven_Multi[];
|
||||
extern const u8 Debug_EventScript_PrintTimeOfDay[];
|
||||
extern const u8 Debug_EventScript_TellTheTime[];
|
||||
@ -393,6 +412,17 @@ static const u8 *const gTimeOfDayStringsTable[TIMES_OF_DAY_COUNT] = {
|
||||
COMPOUND_STRING("Night"),
|
||||
};
|
||||
|
||||
// Follower NPC
|
||||
|
||||
static const u8 *const gFollowerNPCStringsTable[DEBUG_FNPC_COUNT] = {
|
||||
COMPOUND_STRING("Brendan"),
|
||||
COMPOUND_STRING("May"),
|
||||
COMPOUND_STRING("Steven"),
|
||||
COMPOUND_STRING("Wally"),
|
||||
COMPOUND_STRING("Red"),
|
||||
COMPOUND_STRING("Leaf"),
|
||||
};
|
||||
|
||||
// Flags/Vars Menu
|
||||
static const u8 sDebugText_FlagsVars_VariableHex[] = _("{STR_VAR_1}{CLEAR_TO 90}\n0x{STR_VAR_2}{CLEAR_TO 90}");
|
||||
static const u8 sDebugText_FlagsVars_Variable[] = _("Var: {STR_VAR_1}{CLEAR_TO 90}\nVal: {STR_VAR_3}{CLEAR_TO 90}\n{STR_VAR_2}");
|
||||
@ -454,6 +484,17 @@ static const struct DebugMenuOption sDebugMenu_Actions_TimeMenu_Weekdays[] =
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const struct DebugMenuOption sDebugMenu_Actions_FollowerNPCMenu_Create[] =
|
||||
{
|
||||
[DEBUG_FNPC_BRENDAN] = { gFollowerNPCStringsTable[DEBUG_FNPC_BRENDAN], DebugAction_CreateFollowerNPC },
|
||||
[DEBUG_FNPC_MAY] = { gFollowerNPCStringsTable[DEBUG_FNPC_MAY], DebugAction_CreateFollowerNPC },
|
||||
[DEBUG_FNPC_STEVEN] = { gFollowerNPCStringsTable[DEBUG_FNPC_STEVEN], DebugAction_CreateFollowerNPC },
|
||||
[DEBUG_FNPC_WALLY] = { gFollowerNPCStringsTable[DEBUG_FNPC_WALLY], DebugAction_CreateFollowerNPC },
|
||||
[DEBUG_FNPC_RED] = { gFollowerNPCStringsTable[DEBUG_FNPC_RED], DebugAction_CreateFollowerNPC },
|
||||
[DEBUG_FNPC_LEAF] = { gFollowerNPCStringsTable[DEBUG_FNPC_LEAF], DebugAction_CreateFollowerNPC },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const struct DebugMenuOption sDebugMenu_Actions_TimeMenu[] =
|
||||
{
|
||||
{ COMPOUND_STRING("Get time…"), DebugAction_ExecuteScript, Debug_EventScript_TellTheTime },
|
||||
@ -475,6 +516,13 @@ static const struct DebugMenuOption sDebugMenu_Actions_BerryFunctions[] =
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const struct DebugMenuOption sDebugMenu_Actions_FollowerNPCMenu[] =
|
||||
{
|
||||
{ COMPOUND_STRING("Create Follower"), DebugAction_OpenSubMenuCreateFollowerNPC, sDebugMenu_Actions_FollowerNPCMenu_Create },
|
||||
{ COMPOUND_STRING("Destroy Follower"), DebugAction_DestroyFollowerNPC },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const struct DebugMenuOption sDebugMenu_Actions_Utilities[] =
|
||||
{
|
||||
{ COMPOUND_STRING("Fly to map…"), DebugAction_Util_Fly },
|
||||
@ -486,6 +534,7 @@ static const struct DebugMenuOption sDebugMenu_Actions_Utilities[] =
|
||||
{ COMPOUND_STRING("Cheat start"), DebugAction_Util_CheatStart },
|
||||
{ COMPOUND_STRING("Berry Functions…"), DebugAction_OpenSubMenu, sDebugMenu_Actions_BerryFunctions },
|
||||
{ COMPOUND_STRING("EWRAM Counters…"), DebugAction_ExecuteScript, Debug_EventScript_EWRAMCounters },
|
||||
{ COMPOUND_STRING("Follower NPC…"), DebugAction_OpenSubMenu, sDebugMenu_Actions_FollowerNPCMenu },
|
||||
{ COMPOUND_STRING("Steven Multi"), DebugAction_ExecuteScript, Debug_EventScript_Steven_Multi },
|
||||
{ NULL }
|
||||
};
|
||||
@ -766,7 +815,8 @@ static bool32 IsSubMenuAction(const void *action)
|
||||
{
|
||||
return action == DebugAction_OpenSubMenu
|
||||
|| action == DebugAction_OpenSubMenuFlagsVars
|
||||
|| action == DebugAction_OpenSubMenuFakeRTC;
|
||||
|| action == DebugAction_OpenSubMenuFakeRTC
|
||||
|| action == DebugAction_OpenSubMenuCreateFollowerNPC;
|
||||
}
|
||||
|
||||
static void Debug_ShowMenu(DebugFunc HandleInput, const struct DebugMenuOption *items)
|
||||
@ -1206,6 +1256,19 @@ static void DebugAction_ExecuteScript(u8 taskId, const u8 *script)
|
||||
Debug_DestroyMenu_Full_Script(taskId, script);
|
||||
}
|
||||
|
||||
static void DebugAction_OpenSubMenuCreateFollowerNPC(u8 taskId, const struct DebugMenuOption *items)
|
||||
{
|
||||
if (FNPC_ENABLE_NPC_FOLLOWERS)
|
||||
{
|
||||
Debug_DestroyMenu(taskId);
|
||||
Debug_ShowMenu(DebugTask_HandleMenuInput_General, items);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug_DestroyMenu_Full_Script(taskId, Debug_Follower_NPC_Not_Enabled);
|
||||
}
|
||||
}
|
||||
|
||||
// *******************************
|
||||
// Actions Utilities
|
||||
|
||||
@ -3272,6 +3335,49 @@ static void DebugAction_Sound_MUS_SelectId(u8 taskId)
|
||||
}
|
||||
}
|
||||
|
||||
static const u32 gDebugFollowerNPCGraphics[] =
|
||||
{
|
||||
OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL,
|
||||
OBJ_EVENT_GFX_RIVAL_MAY_NORMAL,
|
||||
OBJ_EVENT_GFX_STEVEN,
|
||||
OBJ_EVENT_GFX_WALLY,
|
||||
OBJ_EVENT_GFX_RED,
|
||||
OBJ_EVENT_GFX_LEAF,
|
||||
};
|
||||
|
||||
static void DebugAction_CreateFollowerNPC(u8 taskId)
|
||||
{
|
||||
u32 input = ListMenu_ProcessInput(gTasks[taskId].tMenuTaskId);
|
||||
u32 gfx = gDebugFollowerNPCGraphics[input];
|
||||
|
||||
Debug_DestroyMenu_Full(taskId);
|
||||
LockPlayerFieldControls();
|
||||
DestroyFollowerNPC();
|
||||
SetFollowerNPCData(FNPC_DATA_BATTLE_PARTNER, PARTNER_STEVEN);
|
||||
CreateFollowerNPC(gfx, FNPC_ALL, Debug_Follower_NPC_Event_Script);
|
||||
if (gfx != OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL && gfx != OBJ_EVENT_GFX_RIVAL_MAY_NORMAL)
|
||||
{
|
||||
u32 flags = GetFollowerNPCData(FNPC_DATA_FOLLOWER_FLAGS);
|
||||
SetFollowerNPCData(FNPC_DATA_FOLLOWER_FLAGS, (flags &= ~FNPC_RUNNING));
|
||||
}
|
||||
UnlockPlayerFieldControls();
|
||||
}
|
||||
|
||||
static void DebugAction_DestroyFollowerNPC(u8 taskId)
|
||||
{
|
||||
if (FNPC_ENABLE_NPC_FOLLOWERS)
|
||||
{
|
||||
Debug_DestroyMenu_Full(taskId);
|
||||
LockPlayerFieldControls();
|
||||
DestroyFollowerNPC();
|
||||
UnlockPlayerFieldControls();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug_DestroyMenu_Full_Script(taskId, Debug_Follower_NPC_Not_Enabled);
|
||||
}
|
||||
}
|
||||
|
||||
#undef tCurrentSong
|
||||
|
||||
#undef tMenuTaskId
|
||||
|
||||
@ -49,7 +49,6 @@
|
||||
static void SetFollowerNPCScriptPointer(const u8 *script);
|
||||
static void PlayerLogCoordinates(struct ObjectEvent *player);
|
||||
static void TurnNPCIntoFollower(u32 localId, u32 followerFlags, u32 setScript, const u8 *script);
|
||||
static void CreateFollowerNPC(u32 gfx, u32 followerFlags, const u8 *scriptPtr);
|
||||
static u32 GetFollowerNPCSprite(void);
|
||||
static bool32 IsStateMovement(u32 state);
|
||||
static u32 GetPlayerFaceToDoorDirection(struct ObjectEvent *player, struct ObjectEvent *follower);
|
||||
@ -227,45 +226,6 @@ static void TurnNPCIntoFollower(u32 localId, u32 followerFlags, u32 setScript, c
|
||||
FollowerNPC_HandleSprite();
|
||||
}
|
||||
|
||||
static void CreateFollowerNPC(u32 gfx, u32 followerFlags, const u8 *scriptPtr)
|
||||
{
|
||||
struct ObjectEvent *player = &gObjectEvents[gPlayerAvatar.objectEventId];
|
||||
struct ObjectEvent *follower;
|
||||
struct ObjectEventTemplate npc =
|
||||
{
|
||||
.localId = OBJ_EVENT_ID_NPC_FOLLOWER,
|
||||
.graphicsId = gfx,
|
||||
.x = player->currentCoords.x,
|
||||
.y = player->currentCoords.y,
|
||||
.elevation = PlayerGetElevation(),
|
||||
.script = scriptPtr
|
||||
};
|
||||
|
||||
SetFollowerNPCData(FNPC_DATA_OBJ_ID, TrySpawnObjectEventTemplate(&npc, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, player->currentCoords.x, player->currentCoords.y));
|
||||
follower = &gObjectEvents[GetFollowerNPCData(FNPC_DATA_OBJ_ID)];
|
||||
follower->movementType = MOVEMENT_TYPE_NONE;
|
||||
gSprites[follower->spriteId].callback = MovementType_None;
|
||||
|
||||
SetFollowerNPCData(FNPC_DATA_IN_PROGRESS, TRUE);
|
||||
SetFollowerNPCData(FNPC_DATA_GFX_ID, follower->graphicsId);
|
||||
SetFollowerNPCData(FNPC_DATA_FOLLOWER_FLAGS, followerFlags);
|
||||
SetFollowerNPCData(FNPC_DATA_SURF_BLOB, FNPC_SURF_BLOB_NONE);
|
||||
SetFollowerNPCData(FNPC_DATA_COME_OUT_DOOR, FNPC_DOOR_NONE);
|
||||
SetFollowerNPCScriptPointer(scriptPtr);
|
||||
|
||||
// If the player is biking and the follower flags prohibit biking, force the player to dismount the bike.
|
||||
if (!CheckFollowerNPCFlag(FOLLOWER_NPC_FLAG_CAN_BIKE)
|
||||
&& TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_BIKE))
|
||||
SetPlayerAvatarTransitionFlags(PLAYER_AVATAR_FLAG_ON_FOOT);
|
||||
|
||||
// Set the follower sprite to match the player state.
|
||||
if (!TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_ON_FOOT))
|
||||
FollowerNPC_HandleSprite();
|
||||
|
||||
HideNPCFollower();
|
||||
SetFollowerNPCData(FNPC_DATA_WARP_END, FNPC_WARP_REAPPEAR);
|
||||
}
|
||||
|
||||
static u32 GetFollowerNPCSprite(void)
|
||||
{
|
||||
u32 i;
|
||||
@ -712,6 +672,58 @@ static void CalculateFollowerNPCEscalatorTrajectoryDown(struct Task *task)
|
||||
|
||||
#undef tCounter
|
||||
|
||||
void CreateFollowerNPC(u32 gfx, u32 followerFlags, const u8 *scriptPtr)
|
||||
{
|
||||
if (PlayerHasFollowerNPC())
|
||||
return;
|
||||
|
||||
struct ObjectEvent *player = &gObjectEvents[gPlayerAvatar.objectEventId];
|
||||
struct ObjectEvent *follower;
|
||||
struct ObjectEventTemplate npc =
|
||||
{
|
||||
.localId = OBJ_EVENT_ID_NPC_FOLLOWER,
|
||||
.graphicsId = gfx,
|
||||
.x = player->currentCoords.x,
|
||||
.y = player->currentCoords.y,
|
||||
.elevation = PlayerGetElevation(),
|
||||
.script = scriptPtr
|
||||
};
|
||||
|
||||
SetFollowerNPCData(FNPC_DATA_OBJ_ID, TrySpawnObjectEventTemplate(&npc, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, player->currentCoords.x, player->currentCoords.y));
|
||||
follower = &gObjectEvents[GetFollowerNPCData(FNPC_DATA_OBJ_ID)];
|
||||
follower->movementType = MOVEMENT_TYPE_NONE;
|
||||
gSprites[follower->spriteId].callback = MovementType_None;
|
||||
|
||||
SetFollowerNPCData(FNPC_DATA_IN_PROGRESS, TRUE);
|
||||
SetFollowerNPCData(FNPC_DATA_GFX_ID, follower->graphicsId);
|
||||
SetFollowerNPCData(FNPC_DATA_FOLLOWER_FLAGS, followerFlags);
|
||||
SetFollowerNPCData(FNPC_DATA_SURF_BLOB, FNPC_SURF_BLOB_NONE);
|
||||
SetFollowerNPCData(FNPC_DATA_COME_OUT_DOOR, FNPC_DOOR_NONE);
|
||||
SetFollowerNPCScriptPointer(scriptPtr);
|
||||
|
||||
// If the player is biking and the follower flags prohibit biking, force the player to dismount the bike.
|
||||
if (!CheckFollowerNPCFlag(FOLLOWER_NPC_FLAG_CAN_BIKE)
|
||||
&& TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_BIKE))
|
||||
SetPlayerAvatarTransitionFlags(PLAYER_AVATAR_FLAG_ON_FOOT);
|
||||
|
||||
// Set the follower sprite to match the player state.
|
||||
if (!TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_ON_FOOT))
|
||||
FollowerNPC_HandleSprite();
|
||||
|
||||
HideNPCFollower();
|
||||
SetFollowerNPCData(FNPC_DATA_WARP_END, FNPC_WARP_REAPPEAR);
|
||||
}
|
||||
|
||||
void DestroyFollowerNPC(void)
|
||||
{
|
||||
if (!PlayerHasFollowerNPC())
|
||||
return;
|
||||
|
||||
RemoveObjectEvent(&gObjectEvents[GetFollowerNPCData(FNPC_DATA_OBJ_ID)]);
|
||||
ClearFollowerNPCData();
|
||||
UpdateFollowingPokemon();
|
||||
}
|
||||
|
||||
#define RETURN_STATE(state, dir) return newState == MOVEMENT_INVALID ? state + (dir - 1) : ReturnFollowerNPCDelayedState(dir - 1);
|
||||
u32 DetermineFollowerNPCState(struct ObjectEvent *follower, u32 state, u32 direction)
|
||||
{
|
||||
@ -1642,7 +1654,7 @@ void ScriptCreateFollowerNPC(struct ScriptContext *ctx)
|
||||
const u8 *script = (const u8 *)ScriptReadWord(ctx);
|
||||
u32 battlePartner = ScriptReadHalfword(ctx);
|
||||
|
||||
if (PlayerHasFollowerNPC())
|
||||
if (!FNPC_ENABLE_NPC_FOLLOWERS || PlayerHasFollowerNPC())
|
||||
return;
|
||||
|
||||
SetFollowerNPCData(FNPC_DATA_BATTLE_PARTNER, battlePartner);
|
||||
@ -1651,12 +1663,7 @@ void ScriptCreateFollowerNPC(struct ScriptContext *ctx)
|
||||
|
||||
void ScriptDestroyFollowerNPC(struct ScriptContext *ctx)
|
||||
{
|
||||
if (!PlayerHasFollowerNPC())
|
||||
return;
|
||||
|
||||
RemoveObjectEvent(&gObjectEvents[GetFollowerNPCData(FNPC_DATA_OBJ_ID)]);
|
||||
ClearFollowerNPCData();
|
||||
UpdateFollowingPokemon();
|
||||
DestroyFollowerNPC();
|
||||
}
|
||||
|
||||
void ScriptFaceFollowerNPC(struct ScriptContext *ctx)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user