-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Move Item
Scyrous edited this page Aug 8, 2024
·
6 revisions
Credits: Zeturic, Deokishisu
Adds a MOVE option to the ITEM menu which allows you to move held items directly between Pokémon in your party, instead of having to use the bag as a middle man. Originally posted by Zeturic in this pokecommunity post. This guide also includes the mail fix by Deokishisu in this post and the pokeemerald code is much more recent.
Lastly, when two items are swapped, the dialogue box will now display all four buffered strings (two Pokémon, two items) in just two lines of dialogue, rather than four lines. This has been tested with max length Pokémon/item names in mind.
+extern const u8 gMenuText_Move[];
extern const u8 gText_MoveItemWhere[];
extern const u8 gText_XsYAnd[];
extern const u8 gText_XsYWereSwapped[];
#endif // GUARD_STRINGS_H
const u8 gText_Berry[] = _("BERRY");
const u8 gText_Berries[] = _("BERRIES");
+const u8 gMenuText_Move[] = _("MOVE");
+const u8 gText_MoveItemWhere[] = _("Move item to where?");
+const u8 gText_XsYAnd[] = _("{STR_VAR_1}'s {STR_VAR_2} and\n");
+const u8 gText_XsYWereSwapped[] = _("{STR_VAR_1}'s {STR_VAR_2} were swapped!{PAUSE_UNTIL_PRESS}");
static void CursorCb_Cancel1(u8);
static void CursorCb_Item(u8);
static void CursorCb_Give(u8);
static void CursorCb_TakeItem(u8);
+static void CursorCb_MoveItem(u8);
static void CursorCb_Mail(u8);
static void CursorCb_Read(u8);
static void CursorCb_TakeMail(u8);
static void CursorCb_Cancel2(u8);
Also:
enum {
MENU_SUMMARY,
MENU_SWITCH,
MENU_CANCEL1,
MENU_ITEM,
MENU_GIVE,
MENU_TAKE_ITEM,
+ MENU_MOVE_ITEM,
MENU_MAIL,
MENU_TAKE_MAIL,
MENU_READ,
At the end of the file, add the following two functions:
void CursorCb_MoveItemCallback(u8 taskId)
{
u16 item1, item2;
u8 buffer[100];
if (gPaletteFade.active || MenuHelpers_ShouldWaitForLinkRecv())
return;
switch (PartyMenuButtonHandler(&gPartyMenu.slotId2))
{
case 2: // User hit B or A while on Cancel
HandleChooseMonCancel(taskId, &gPartyMenu.slotId2);
break;
case 1: // User hit A on a Pokemon
// Pokemon can't give away items to eggs or themselves
if (GetMonData(&gPlayerParty[gPartyMenu.slotId2], MON_DATA_IS_EGG)
|| gPartyMenu.slotId == gPartyMenu.slotId2)
{
PlaySE(SE_FAILURE);
return;
}
if(GetMonData(&gPlayerParty[gPartyMenu.slotId2], MON_DATA_HELD_ITEM) >= ITEM_ORANGE_MAIL && GetMonData(&gPlayerParty[gPartyMenu.slotId2], MON_DATA_HELD_ITEM) <= ITEM_RETRO_MAIL)
{
PlaySE(SE_FAILURE);
return;
}
PlaySE(SE_SELECT);
gPartyMenu.action = PARTY_ACTION_CHOOSE_MON;
// look up held items
item1 = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_HELD_ITEM);
item2 = GetMonData(&gPlayerParty[gPartyMenu.slotId2], MON_DATA_HELD_ITEM);
// swap the held items
SetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_HELD_ITEM, &item2);
SetMonData(&gPlayerParty[gPartyMenu.slotId2], MON_DATA_HELD_ITEM, &item1);
// update the held item icons
UpdatePartyMonHeldItemSprite(
&gPlayerParty[gPartyMenu.slotId],
&sPartyMenuBoxes[gPartyMenu.slotId]
);
UpdatePartyMonHeldItemSprite(
&gPlayerParty[gPartyMenu.slotId2],
&sPartyMenuBoxes[gPartyMenu.slotId2]
);
// create the string describing the move
if (item2 == ITEM_NONE)
{
GetMonNickname(&gPlayerParty[gPartyMenu.slotId2], gStringVar1);
CopyItemName(item1, gStringVar2);
StringExpandPlaceholders(gStringVar4, gText_PkmnWasGivenItem);
}
else
{
GetMonNickname(&gPlayerParty[gPartyMenu.slotId], gStringVar1);
CopyItemName(item1, gStringVar2);
StringExpandPlaceholders(buffer, gText_XsYAnd);
StringAppend(buffer, gText_XsYWereSwapped);
GetMonNickname(&gPlayerParty[gPartyMenu.slotId2], gStringVar1);
CopyItemName(item2, gStringVar2);
StringExpandPlaceholders(gStringVar4, buffer);
}
// display the string
DisplayPartyMenuMessage(gStringVar4, TRUE);
// update colors of selected boxes
AnimatePartySlot(gPartyMenu.slotId2, 0);
AnimatePartySlot(gPartyMenu.slotId, 1);
// return to the main party menu
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = Task_UpdateHeldItemSprite;
break;
}
}
void CursorCb_MoveItem(u8 taskId)
{
struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId];
PlaySE(SE_SELECT);
// delete old windows
PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]);
PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]);
if (GetMonData(mon, MON_DATA_HELD_ITEM) != ITEM_NONE)
{
gPartyMenu.action = PARTY_ACTION_SWITCH;
// show "Move item to where" in bottom left
DisplayPartyMenuStdMessage(PARTY_MSG_MOVE_ITEM_WHERE);
// update color of first selected box
AnimatePartySlot(gPartyMenu.slotId, 1);
// set up callback
gPartyMenu.slotId2 = gPartyMenu.slotId;
gTasks[taskId].func = CursorCb_MoveItemCallback;
}
else
{
// create and display string about lack of hold item
GetMonNickname(mon, gStringVar1);
StringExpandPlaceholders(gStringVar4, gText_PkmnNotHolding);
DisplayPartyMenuMessage(gStringVar4, TRUE);
// return to the main party menu
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = Task_UpdateHeldItemSprite;
}
}
#define PARTY_MSG_BOOST_PP_WHICH_MOVE 23
#define PARTY_MSG_DO_WHAT_WITH_ITEM 24
#define PARTY_MSG_DO_WHAT_WITH_MAIL 25
#define PARTY_MSG_ALREADY_HOLDING_ONE 26
+#define PARTY_MSG_MOVE_ITEM_WHERE 27
#define PARTY_MSG_NONE 127
struct
{
const u8 *text;
TaskFunc func;
} static const sCursorOptions[] =
{
[MENU_SUMMARY] = {gText_Summary5, CursorCb_Summary},
[MENU_SWITCH] = {gText_Switch2, CursorCb_Switch},
[MENU_CANCEL1] = {gText_Cancel2, CursorCb_Cancel1},
[MENU_ITEM] = {gText_Item, CursorCb_Item},
[MENU_GIVE] = {gMenuText_Give, CursorCb_Give},
[MENU_TAKE_ITEM] = {gText_Take, CursorCb_TakeItem},
+ [MENU_MOVE_ITEM] = {gMenuText_Move, CursorCb_MoveItem},
[MENU_MAIL] = {gText_Mail, CursorCb_Mail},
[MENU_TAKE_MAIL] = {gText_Take2, CursorCb_TakeMail},
Also:
static const u8 *const sActionStringTable[] =
{
[PARTY_MSG_CHOOSE_MON] = gText_ChoosePokemon,
[PARTY_MSG_CHOOSE_MON_OR_CANCEL] = gText_ChoosePokemonCancel,
[PARTY_MSG_CHOOSE_MON_AND_CONFIRM] = gText_ChoosePokemonConfirm,
[PARTY_MSG_MOVE_TO_WHERE] = gText_MoveToWhere,
[PARTY_MSG_TEACH_WHICH_MON] = gText_TeachWhichPokemon,
[PARTY_MSG_USE_ON_WHICH_MON] = gText_UseOnWhichPokemon,
[PARTY_MSG_GIVE_TO_WHICH_MON] = gText_GiveToWhichPokemon,
[PARTY_MSG_NOTHING_TO_CUT] = gText_NothingToCut,
[PARTY_MSG_CANT_SURF_HERE] = gText_CantSurfHere,
[PARTY_MSG_ALREADY_SURFING] = gText_AlreadySurfing,
[PARTY_MSG_CURRENT_TOO_FAST] = gText_CurrentIsTooFast,
[PARTY_MSG_ENJOY_CYCLING] = gText_EnjoyCycling,
[PARTY_MSG_ALREADY_IN_USE] = gText_InUseAlready_PM,
[PARTY_MSG_CANT_USE_HERE] = gText_CantUseHere,
[PARTY_MSG_NO_MON_FOR_BATTLE] = gText_NoPokemonForBattle,
[PARTY_MSG_CHOOSE_MON_2] = gText_ChoosePokemon2,
[PARTY_MSG_NOT_ENOUGH_HP] = gText_NotEnoughHp,
[PARTY_MSG_X_MONS_ARE_NEEDED] = gText_PokemonAreNeeded,
[PARTY_MSG_MONS_CANT_BE_SAME] = gText_PokemonCantBeSame,
[PARTY_MSG_NO_SAME_HOLD_ITEMS] = gText_NoIdenticalHoldItems,
[PARTY_MSG_UNUSED] = gText_EmptyString2,
[PARTY_MSG_DO_WHAT_WITH_MON] = gText_DoWhatWithPokemon,
[PARTY_MSG_RESTORE_WHICH_MOVE] = gText_RestoreWhichMove,
[PARTY_MSG_BOOST_PP_WHICH_MOVE] = gText_BoostPp,
[PARTY_MSG_DO_WHAT_WITH_ITEM] = gText_DoWhatWithItem,
[PARTY_MSG_DO_WHAT_WITH_MAIL] = gText_DoWhatWithMail,
[PARTY_MSG_ALREADY_HOLDING_ONE] = gText_AlreadyHoldingOne,
+ [PARTY_MSG_MOVE_ITEM_WHERE] = gText_MoveItemWhere,
};
And also:
static const u8 sPartyMenuAction_NoEntrySummaryCancel[] = {MENU_NO_ENTRY, MENU_SUMMARY, MENU_CANCEL1};
static const u8 sPartyMenuAction_StoreSummaryCancel[] = {MENU_STORE, MENU_SUMMARY, MENU_CANCEL1};
-static const u8 sPartyMenuAction_GiveTakeItemCancel[] = {MENU_GIVE, MENU_TAKE_ITEM, MENU_CANCEL2};
+static const u8 sPartyMenuAction_GiveTakeItemCancel[] = {MENU_GIVE, MENU_TAKE_ITEM, MENU_MOVE_ITEM, MENU_CANCEL2};
static const u8 sPartyMenuAction_ReadTakeMailCancel[] = {MENU_READ, MENU_TAKE_MAIL, MENU_CANCEL2};
static const u8 sPartyMenuAction_RegisterSummaryCancel[] = {MENU_REGISTER, MENU_SUMMARY, MENU_CANCEL1};
And finally:
static const struct WindowTemplate sItemGiveTakeWindowTemplate =
{
.bg = 2,
.tilemapLeft = 23,
- .tilemapTop = 13,
+ .tilemapTop = 11,
.width = 6,
- .height = 6,
+ .height = 8,
.paletteNum = 14,
.baseBlock = 0x39D,
};
That is all!