-
Notifications
You must be signed in to change notification settings - Fork 2k
Holding Select Allows For A Second Register Item
voloved edited this page Aug 31, 2023
·
5 revisions
By devolov
*Goal: Make it possible to register two items; one by pressing select as usual, and one by holding select.
--------------------- graphics/bag/select_button_hold.png ---------------------
Add the new item to register into the save data. Saving it in a way where it takes space from unused_3598
allows save compatibility older sav files.
------------------------------- include/global.h -------------------------------
index 3567c7b9f..8c93e2961 100644
@@ -1019,9 +1019,10 @@ struct SaveBlock1
/*0x322C*/ struct MysteryGiftSave mysteryGift;
struct ItemSlot bagPocket_Medicine[BAG_MEDICINE_COUNT];
struct ItemSlot bagPocket_BattleItems[BAG_BATTLEITEMS_COUNT];
struct ItemSlot bagPocket_Treasures[BAG_TREASURES_COUNT];
- /*0x3598*/ u8 unused_3598[0x180];
+ /*0x3598*/ u8 unused_3598[0x17E];
+ /*0x3716*/ u16 registeredLongItem; // registered for long press of SELECT button
/*0x3718*/ u32 trainerHillTimes[NUM_TRAINER_HILL_MODES];
/*0x3728*/ struct RamScript ramScript;
/*0x3B14*/ struct RecordMixingGift recordMixingGift;
/*0x3B24*/ u8 seen2[NUM_DEX_FLAG_BYTES];
Add in logic to detect when the player either held the Select key or released it before the holding timeout.
The hold time-out here is set to 60 cycles, which is about 1.5 seconds measured off a stopwatch.
-------------------------- src/field_control_avatar.c --------------------------
index 45c1c803e..b6eaaf023 100644
@@ -40,8 +40,9 @@
static EWRAM_DATA u8 sWildEncounterImmunitySteps = 0;
static EWRAM_DATA u16 sPrevMetatileBehavior = 0;
static EWRAM_DATA u8 sCurrentDirection = 0;
static EWRAM_DATA u8 sPreviousDirection = 0;
+static EWRAM_DATA u8 sPlayerSelectHoldFrames = 0;
u8 gSelectedObjectEvent;
static void SetDirectionFromHeldKeys(u16 heldKeys);
@@ -88,8 +89,10 @@ void FieldClearPlayerInput(struct FieldInput *input)
input->input_field_1_0 = FALSE;
input->input_field_1_1 = FALSE;
input->input_field_1_2 = FALSE;
input->input_field_1_3 = FALSE;
+ input->input_field_1_6 = FALSE;
+ input->input_field_1_7 = FALSE;
input->dpadDirection = 0;
}
void FieldGetPlayerInput(struct FieldInput *input, u16 newKeys, u16 heldKeys)
@@ -109,8 +112,21 @@ void FieldGetPlayerInput(struct FieldInput *input, u16 newKeys, u16 heldKeys)
if (newKeys & A_BUTTON)
input->pressedAButton = TRUE;
if (newKeys & B_BUTTON)
input->pressedBButton = TRUE;
+
+ if (sPlayerSelectHoldFrames == 60)
+ input->input_field_1_7 = TRUE;
+ if (JOY_HELD(SELECT_BUTTON))
+ sPlayerSelectHoldFrames = sPlayerSelectHoldFrames < 0xFF ? sPlayerSelectHoldFrames + 1 : 0xFF;
+ else if (sPlayerSelectHoldFrames != 0)
+ {
+ if (sPlayerSelectHoldFrames < 60)
+ input->input_field_1_6 = TRUE;
+ sPlayerSelectHoldFrames = 0;
+ }
}
if (heldKeys & (DPAD_UP | DPAD_DOWN | DPAD_LEFT | DPAD_RIGHT))
{
@@ -197,9 +213,12 @@ int ProcessPlayerFieldInput(struct FieldInput *input)
PlaySE(SE_WIN_OPEN);
ShowStartMenu();
return TRUE;
}
- if (input->pressedSelectButton && UseRegisteredKeyItemOnField() == TRUE)
+ if (input->input_field_1_6 && UseRegisteredKeyItemOnField(FALSE) == TRUE)
+ return TRUE;
+
+ if (input->input_field_1_7 && UseRegisteredKeyItemOnField(TRUE) == TRUE)
return TRUE;
if(TX_DEBUG_SYSTEM_ENABLE == TRUE && TX_DEBUG_SYSTEM_IN_MENU == FALSE && input->input_field_1_2)
{
------------------------ include/field_control_avatar.h ------------------------
index e02fcd5af..99ceb154c 100644
@@ -16,10 +16,10 @@ struct FieldInput
bool8 input_field_1_2:1;
bool8 input_field_1_3:1;
bool8 input_field_1_4:1;
bool8 input_field_1_5:1;
- bool8 input_field_1_6:1;
- bool8 input_field_1_7:1;
+ bool8 input_field_1_6:1; // Used to detect registered item tapping select
+ bool8 input_field_1_7:1; // Used to detect registered item holding select
u8 dpadDirection;
};
void FieldClearPlayerInput(struct FieldInput *pStruct);
------------------------------- src/item_menu.c -------------------------------
index 04608de70..066ff9859 100755
@@ -95,8 +95,10 @@ enum {
ACTION_BY_NAME,
ACTION_BY_TYPE,
ACTION_BY_AMOUNT,
ACTION_BY_NUMBER,
+ ACTION_REGISTER_TAP,
+ ACTION_REGISTER_HOLD,
ACTION_DUMMY,
};
enum {
@@ -203,8 +205,10 @@ static void BagMenu_MoveCursorCallback(s32, bool8, struct ListMenu *);
static void BagMenu_ItemPrintCallback(u8, u32, u8);
static void ItemMenu_UseOutOfBattle(u8);
static void ItemMenu_Toss(u8);
static void ItemMenu_Register(u8);
+static void ItemMenu_RegisterHold(u8);
+static void ItemMenu_CheckWhichRegister(u8);
static void ItemMenu_Give(u8);
static void ItemMenu_Cancel(u8);
static void ItemMenu_UseInBattle(u8);
static void ItemMenu_CheckTag(u8);
@@ -294,18 +298,21 @@ static const struct ListMenuTemplate sItemListMenu
+static const u8 sMenuText_Tap[] = _("Tap");
+static const u8 sMenuText_Hold[] = _("Hold");
+static const u8 sText_RegisterHow[] = _("Register this\nitem by tapping or\nholding SELECT?");
static const struct MenuAction sItemMenuActions[] = {
[ACTION_USE] = {gMenuText_Use, ItemMenu_UseOutOfBattle},
[ACTION_TOSS] = {gMenuText_Toss, ItemMenu_Toss},
- [ACTION_REGISTER] = {gMenuText_Register, ItemMenu_Register},
+ [ACTION_REGISTER] = {gMenuText_Register, ItemMenu_CheckWhichRegister},
[ACTION_GIVE] = {gMenuText_Give, ItemMenu_Give},
[ACTION_CANCEL] = {gText_Cancel2, ItemMenu_Cancel},
[ACTION_BATTLE_USE] = {gMenuText_Use, ItemMenu_UseInBattle},
[ACTION_CHECK] = {gMenuText_Check, ItemMenu_UseOutOfBattle},
[ACTION_WALK] = {gMenuText_Walk, ItemMenu_UseOutOfBattle},
- [ACTION_DESELECT] = {gMenuText_Deselect, ItemMenu_Register},
+ [ACTION_DESELECT] = {gMenuText_Deselect, ItemMenu_CheckWhichRegister},
[ACTION_CHECK_TAG] = {gMenuText_CheckTag, ItemMenu_CheckTag},
[ACTION_CONFIRM] = {gMenuText_Confirm, Task_FadeAndCloseBagMenu},
[ACTION_SHOW] = {gMenuText_Show, ItemMenu_Show},
[ACTION_GIVE_FAVOR_LADY] = {gMenuText_Give2, ItemMenu_GiveFavorLady},
@@ -313,8 +320,10 @@ static const struct MenuAction sItemMenuActions[] = {
[ACTION_BY_NAME] = {sMenuText_ByName, ItemMenu_SortByName},
[ACTION_BY_TYPE] = {sMenuText_ByType, ItemMenu_SortByType},
[ACTION_BY_NUMBER] = {sMenuText_ByNumber, ItemMenu_SortByID},
[ACTION_BY_AMOUNT] = {sMenuText_ByAmount, ItemMenu_SortByAmount},
+ [ACTION_REGISTER_TAP] = {sMenuText_Tap, ItemMenu_Register},
+ [ACTION_REGISTER_HOLD] = {sMenuText_Hold, ItemMenu_RegisterHold},
[ACTION_DUMMY] = {gText_EmptyString2, NULL}
};
// these are all 2D arrays with a width of 2 but are represented as 1D arrays
@@ -373,8 +382,14 @@ static const u8 sContextMenuItems_FavorLady[] = {
static const u8 sContextMenuItems_QuizLady[] = {
ACTION_CONFIRM_QUIZ_LADY, ACTION_CANCEL
};
+static const u8 sRegisterOptions[] =
+{
+ ACTION_REGISTER_TAP, ACTION_REGISTER_HOLD,
+ ACTION_DUMMY, ACTION_CANCEL
+};
+
static const TaskFunc sContextMenuFuncs[] = {
[ITEMMENULOCATION_FIELD] = Task_ItemContext_Normal,
[ITEMMENULOCATION_BATTLE] = Task_ItemContext_Normal,
[ITEMMENULOCATION_PARTY] = Task_ItemContext_GiveToParty,
@@ -407,8 +422,9 @@ static const struct ScrollArrowsTemplate sBagScrollArrowsTemplate = {
.palNum = 0,
};
static const u8 sRegisteredSelect_Gfx[] = INCBIN_U8("graphics/bag/select_button.4bpp");
+static const u8 sRegisteredSelectLong_Gfx[] = INCBIN_U8("graphics/bag/select_button_hold.4bpp");
enum {
COLORID_NORMAL,
COLORID_POCKET_NAME,
@@ -695,8 +711,9 @@ void VBlankCB_BagMenuRun(void)
#define tListTaskId data[0]
#define tListPosition data[1]
#define tQuantity data[2]
#define tNeverRead data[3]
+#define tIsRegisterHold data[5]
#define tItemCount data[8]
#define tMsgWindowId data[10]
#define tPocketSwitchDir data[11]
#define tPocketSwitchTimer data[12]
@@ -982,9 +999,9 @@ static void BagMenu_MoveCursorCallback(s32 itemIndex, bool8 onInit, struct ListM
static void BagMenu_ItemPrintCallback(u8 windowId, u32 itemIndex, u8 y)
{
u16 itemId;
u16 itemQuantity;
int offset;
+ int selOff;
if (itemIndex != LIST_CANCEL)
{
if (gBagMenu->toSwapPos != NOT_SWAPPING)
@@ -1017,14 +1034,20 @@ static void BagMenu_ItemPrintCallback(u8 windowId, u32 itemIndex, u8 y)
offset = GetStringRightAlignXOffset(FONT_NARROW, gStringVar4, 119);
BagMenu_Print(windowId, FONT_NARROW, gStringVar4, offset, y, 0, 0, TEXT_SKIP_DRAW, COLORID_NORMAL);
}
else
{
// Print registered icon
if (gSaveBlock1Ptr->registeredItem && gSaveBlock1Ptr->registeredItem == itemId)
BlitBitmapToWindow(windowId, sRegisteredSelect_Gfx, 96, y - 1, 24, 16);
+ else if (gSaveBlock1Ptr->registeredLongItem && gSaveBlock1Ptr->registeredLongItem == itemId)
+ BlitBitmapToWindow(windowId, sRegisteredSelectLong_Gfx, 96, y - 1, 24, 16);
}
}
}
@@ -1682,9 +1712,9 @@ static void OpenContextMenu(u8 taskId)
else{
gBagMenu->contextMenuNumItems = ARRAY_COUNT(sContextMenuItems_KeyItemsPocket);
memcpy(&gBagMenu->contextMenuItemsBuffer, &sContextMenuItems_KeyItemsPocket, sizeof(sContextMenuItems_KeyItemsPocket));
}
- if (gSaveBlock1Ptr->registeredItem == gSpecialVar_ItemId)
+ if (gSaveBlock1Ptr->registeredItem == gSpecialVar_ItemId || gSaveBlock1Ptr->registeredLongItem == gSpecialVar_ItemId)
gBagMenu->contextMenuItemsBuffer[1] = ACTION_DESELECT;
if (gSpecialVar_ItemId == ITEM_MACH_BIKE || gSpecialVar_ItemId == ITEM_ACRO_BIKE)
{
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE))
@@ -1976,20 +2006,64 @@ static void ItemMenu_Register(u8 taskId)
{
s16 *data = gTasks[taskId].data;
u16 *scrollPos = &gBagPosition.scrollPosition[gBagPosition.pocket];
u16 *cursorPos = &gBagPosition.cursorPosition[gBagPosition.pocket];
+ u16 *registerSlot;
- if (gSaveBlock1Ptr->registeredItem == gSpecialVar_ItemId)
- gSaveBlock1Ptr->registeredItem = 0;
+ registerSlot = tIsRegisterHold ? &gSaveBlock1Ptr->registeredLongItem : &gSaveBlock1Ptr->registeredItem;
+ if (*registerSlot == gSpecialVar_ItemId)
+ *registerSlot = 0;
else
- gSaveBlock1Ptr->registeredItem = gSpecialVar_ItemId;
+ *registerSlot = gSpecialVar_ItemId;
+ tIsRegisterHold = FALSE;
DestroyListMenuTask(tListTaskId, scrollPos, cursorPos);
LoadBagItemListBuffers(gBagPosition.pocket);
tListTaskId = ListMenuInit(&gMultiuseListMenuTemplate, *scrollPos, *cursorPos);
ScheduleBgCopyTilemapToVram(0);
ItemMenu_Cancel(taskId);
}
+static void ItemMenu_RegisterHold(u8 taskId)
+{
+ gTasks[taskId].tIsRegisterHold = TRUE;
+ gTasks[taskId].func = ItemMenu_Register;
+}
+
+static void AddRegisterSubMenu(void)
+{
+ gBagMenu->contextMenuItemsPtr = sRegisterOptions;
+ memcpy(&gBagMenu->contextMenuItemsBuffer, &sRegisterOptions, NELEMS(sRegisterOptions));
+ gBagMenu->contextMenuNumItems = NELEMS(sRegisterOptions);
+ StringExpandPlaceholders(gStringVar4, sText_RegisterHow);
+ FillWindowPixelBuffer(1, PIXEL_FILL(0));
+ BagMenu_Print(1, 1, gStringVar4, 3, 1, 0, 0, 0, 0);
+ PrintContextMenuItemGrid(BagMenu_AddWindow(ITEMWIN_2x2), 2, 2);
+}
+
+static void Task_LoadRegisterOptions(u8 taskId)
+{
+ s16 *data = gTasks[taskId].data;
+ if (gSaveBlock1Ptr->registeredItem == gSpecialVar_ItemId){
+ // If the item is already registered, then deselect it.
+ gTasks[taskId].func = ItemMenu_Register;
+ }
+ else if (gSaveBlock1Ptr->registeredLongItem == gSpecialVar_ItemId){
+ // If the item is already registered, then deselect it.
+ gTasks[taskId].func = ItemMenu_RegisterHold;
+ }
+ else{
+ BagDestroyPocketScrollArrowPair();
+ RemoveContextWindow();
+ AddRegisterSubMenu();
+ gTasks[taskId].func = Task_ItemContext_MultipleRows;
+ }
+}
+
+static void ItemMenu_CheckWhichRegister(u8 taskId)
+{
+ gTasks[taskId].func = Task_LoadRegisterOptions;
+}
+
static void ItemMenu_Give(u8 taskId)
{
RemoveContextWindow();
if (!IsWritingMailAllowed(gSpecialVar_ItemId))
@@ -2101,35 +2175,39 @@ static void Task_ItemContext_GiveToPC(u8 taskId)
}
#define tUsingRegisteredKeyItem data[3] // See usage in item_use.c
-bool8 UseRegisteredKeyItemOnField(void)
+bool8 UseRegisteredKeyItemOnField(bool8 isRegisterHold)
{
u8 taskId;
+ u16 item = isRegisterHold ? gSaveBlock1Ptr->registeredLongItem : gSaveBlock1Ptr->registeredItem;
if (InUnionRoom() == TRUE || InBattlePyramid() || InBattlePike() || InMultiPartnerRoom() == TRUE)
return FALSE;
HideMapNamePopUpWindow();
ChangeBgY_ScreenOff(0, 0, BG_COORD_SET);
- if (gSaveBlock1Ptr->registeredItem != ITEM_NONE)
+ if (item != ITEM_NONE)
{
- if (CheckBagHasItem(gSaveBlock1Ptr->registeredItem, 1) == TRUE)
+ if (CheckBagHasItem(item, 1) == TRUE)
{
LockPlayerFieldControls();
FreezeObjectEvents();
PlayerFreeze();
StopPlayerAvatar();
- gSpecialVar_ItemId = gSaveBlock1Ptr->registeredItem;
- taskId = CreateTask(ItemId_GetFieldFunc(gSaveBlock1Ptr->registeredItem), 8);
+ gSpecialVar_ItemId = item;
+ taskId = CreateTask(ItemId_GetFieldFunc(item), 8);
gTasks[taskId].tUsingRegisteredKeyItem = TRUE;
return TRUE;
}
else
{
- gSaveBlock1Ptr->registeredItem = ITEM_NONE;
+ item = ITEM_NONE;
}
}
- ScriptContext_SetupScript(EventScript_SelectWithoutRegisteredItem);
+ if (isRegisterHold)
+ ScriptContext_SetupScript(EventScript_SelectWithoutRegisteredLongItem);
+ else
+ ScriptContext_SetupScript(EventScript_SelectWithoutRegisteredItem);
return TRUE;
}
#undef tUsingRegisteredKeyItem
----------------------------- include/item_menu.h -----------------------------
index ce03cdacb..f65a12cd9 100644
@@ -93,9 +93,9 @@ void CB2_BagMenuFromBattle(void);
void UpdatePocketListPosition(u8 pocketId);
void CB2_ReturnToBagMenuPocket(void);
void CB2_BagMenuFromStartMenu(void);
u8 GetItemListPosition(u8 pocketId);
-bool8 UseRegisteredKeyItemOnField(void);
+bool8 UseRegisteredKeyItemOnField(bool8 isRegisterHold);
void CB2_GoToSellMenu(void);
void GoToBagMenu(u8 bagMenuType, u8 pocketId, void ( *exitCallback)());
void DoWallyTutorialBagMenu(void);
void ResetBagScrollPositions(void);
-------------------------------- src/new_game.c --------------------------------
index aa0a1f240..4b9e5b18e 100644
@@ -189,8 +189,9 @@ void NewGameInitData(void)
ResetPokemonStorageSystem();
ClearRoamerData();
ClearRoamerLocationData();
gSaveBlock1Ptr->registeredItem = 0;
+ gSaveBlock1Ptr->registeredLongItem = 0;
ClearBag();
NewGameInitPCItems();
ClearPokeblocks();
ClearDecorationInventories();
----------------------------- data/event_scripts.s -----------------------------
index 22c15371d..02db7c064 100644
@@ -861,8 +861,12 @@ gText_SandstormIsVicious::
gText_SelectWithoutRegisteredItem::
.string "An item in the BAG can be\n"
.string "registered to SELECT for easy use.$"
+gText_SelectWithoutRegisteredLongItem::
+ .string "A second item in the BAG can be\n"
+ .string "registered to holding SELECT.$"
+
gText_PokemonTrainerSchoolEmail::
.string "There's an e-mail from POKéMON TRAINER\n"
.string "SCHOOL.\p"
.string "… … … … … …\p"
@@ -968,8 +972,12 @@ gText_LegendaryFlewAway::
EventScript_SelectWithoutRegisteredItem::
msgbox gText_SelectWithoutRegisteredItem, MSGBOX_SIGN
end
+EventScript_SelectWithoutRegisteredLongItem::
+ msgbox gText_SelectWithoutRegisteredLongItem, MSGBOX_SIGN
+ end
+
.include "data/scripts/field_poison.inc"
Common_EventScript_NopReturn::
return
--------------------------- include/event_scripts.h ---------------------------
index a64b8ffc4..953f78fc7 100644
@@ -615,8 +615,9 @@ extern const u8 BerryTree_EventScript_ItemUsePlantBerry[];
extern const u8 BerryTree_EventScript_ItemUseWailmerPail[];
extern const u8 BattleFrontier_OutsideEast_EventScript_WaterSudowoodo[];
extern const u8 EventScript_SelectWithoutRegisteredItem[];
+extern const u8 EventScript_SelectWithoutRegisteredLongItem[];
// overworld
extern const u8 EventScript_WhiteOut[];
extern const u8 EventScript_ResetMrBriney[];
--------------------------------- src/item.c ---------------------------------
void SwapRegisteredBike(void)
{
switch (gSaveBlock1Ptr->registeredItem)
{
case ITEM_MACH_BIKE:
gSaveBlock1Ptr->registeredItem = ITEM_ACRO_BIKE;
break;
case ITEM_ACRO_BIKE:
gSaveBlock1Ptr->registeredItem = ITEM_MACH_BIKE;
break;
}
+ switch (gSaveBlock1Ptr->registeredLongItem)
+ {
+ case ITEM_MACH_BIKE:
+ gSaveBlock1Ptr->registeredLongItem = ITEM_ACRO_BIKE;
+ break;
+ case ITEM_ACRO_BIKE:
+ gSaveBlock1Ptr->registeredLongItem = ITEM_MACH_BIKE;
+ break;
+ }
}