diff --git a/include/constants/party_menu.h b/include/constants/party_menu.h index 76360d8ee8..3a7ad372ff 100644 --- a/include/constants/party_menu.h +++ b/include/constants/party_menu.h @@ -83,6 +83,7 @@ #define PARTY_MSG_CHOOSE_SECOND_FUSION 28 #define PARTY_MSG_NO_POKEMON 29 #define PARTY_MSG_CHOOSE_MON_FOR_BOX 30 +#define PARTY_MSG_MOVE_ITEM_WHERE 31 #define PARTY_MSG_NONE 127 diff --git a/include/strings.h b/include/strings.h index 2bc6b23563..a9cddee25b 100644 --- a/include/strings.h +++ b/include/strings.h @@ -1573,6 +1573,9 @@ extern const u8 gText_ChoosePokemon[]; extern const u8 gText_ChoosePokemonCancel[]; extern const u8 gText_ChoosePokemonConfirm[]; extern const u8 gText_SendWhichMonToPC[]; +extern const u8 gText_MoveItemWhere[]; +extern const u8 gText_XsYAnd[]; +extern const u8 gText_XsYWereSwapped[]; extern const u8 gText_MoveToWhere[]; extern const u8 gText_TeachWhichPokemon[]; extern const u8 gText_UseOnWhichPokemon[]; diff --git a/src/data/party_menu.h b/src/data/party_menu.h index 9a2b8c4f78..f8860ac4b0 100644 --- a/src/data/party_menu.h +++ b/src/data/party_menu.h @@ -497,9 +497,9 @@ static const struct WindowTemplate sItemGiveTakeWindowTemplate = { .bg = 2, .tilemapLeft = 23, - .tilemapTop = 13, + .tilemapTop = 11, .width = 6, - .height = 6, + .height = 8, .paletteNum = 14, .baseBlock = 0x39D, }; @@ -661,6 +661,7 @@ static const u8 *const sActionStringTable[] = [PARTY_MSG_CHOOSE_SECOND_FUSION] = gText_NextFusionMon, [PARTY_MSG_NO_POKEMON] = COMPOUND_STRING("You have no POKéMON."), [PARTY_MSG_CHOOSE_MON_FOR_BOX] = gText_SendWhichMonToPC, + [PARTY_MSG_MOVE_ITEM_WHERE] = gText_MoveItemWhere, }; static const u8 *const sDescriptionStringTable[] = @@ -696,33 +697,34 @@ struct TaskFunc func; } static const sCursorOptions[MENU_FIELD_MOVES] = { - [MENU_SUMMARY] = {COMPOUND_STRING("SUMMARY"), CursorCb_Summary}, - [MENU_SWITCH] = {COMPOUND_STRING("SWITCH"), CursorCb_Switch}, - [MENU_CANCEL1] = {gText_Cancel2, CursorCb_Cancel1}, - [MENU_ITEM] = {COMPOUND_STRING("ITEM"), CursorCb_Item}, - [MENU_GIVE] = {gMenuText_Give, CursorCb_Give}, - [MENU_TAKE_ITEM] = {COMPOUND_STRING("TAKE"), CursorCb_TakeItem}, - [MENU_MAIL] = {COMPOUND_STRING("MAIL"), CursorCb_Mail}, - [MENU_TAKE_MAIL] = {COMPOUND_STRING("TAKE"), CursorCb_TakeMail}, - [MENU_READ] = {COMPOUND_STRING("READ"), CursorCb_Read}, - [MENU_CANCEL2] = {gText_Cancel2, CursorCb_Cancel2}, - [MENU_SHIFT] = {COMPOUND_STRING("SHIFT"), CursorCb_SendMon}, - [MENU_SEND_OUT] = {COMPOUND_STRING("SEND OUT"), CursorCb_SendMon}, - [MENU_ENTER] = {COMPOUND_STRING("ENTER"), CursorCb_Enter}, - [MENU_NO_ENTRY] = {COMPOUND_STRING("NO ENTRY"), CursorCb_NoEntry}, - [MENU_STORE] = {COMPOUND_STRING("STORE"), CursorCb_Store}, - [MENU_REGISTER] = {gText_Register, CursorCb_Register}, - [MENU_TRADE1] = {sText_Trade4, CursorCb_Trade1}, - [MENU_TRADE2] = {sText_Trade4, CursorCb_Trade2}, - [MENU_TOSS] = {gMenuText_Toss, CursorCb_Toss}, - [MENU_CATALOG_BULB] = {COMPOUND_STRING("Light bulb"), CursorCb_CatalogBulb}, - [MENU_CATALOG_OVEN] = {COMPOUND_STRING("Microwave oven"), CursorCb_CatalogOven}, + [MENU_SUMMARY] = {COMPOUND_STRING("SUMMARY"), CursorCb_Summary}, + [MENU_SWITCH] = {COMPOUND_STRING("SWITCH"), CursorCb_Switch}, + [MENU_CANCEL1] = {gText_Cancel2, CursorCb_Cancel1}, + [MENU_ITEM] = {COMPOUND_STRING("ITEM"), CursorCb_Item}, + [MENU_GIVE] = {gMenuText_Give, CursorCb_Give}, + [MENU_TAKE_ITEM] = {COMPOUND_STRING("TAKE"), CursorCb_TakeItem}, + [MENU_MOVE_ITEM] = {COMPOUND_STRING("MOVE"), CursorCb_MoveItem}, + [MENU_MAIL] = {COMPOUND_STRING("MAIL"), CursorCb_Mail}, + [MENU_TAKE_MAIL] = {COMPOUND_STRING("TAKE"), CursorCb_TakeMail}, + [MENU_READ] = {COMPOUND_STRING("READ"), CursorCb_Read}, + [MENU_CANCEL2] = {gText_Cancel2, CursorCb_Cancel2}, + [MENU_SHIFT] = {COMPOUND_STRING("SHIFT"), CursorCb_SendMon}, + [MENU_SEND_OUT] = {COMPOUND_STRING("SEND OUT"), CursorCb_SendMon}, + [MENU_ENTER] = {COMPOUND_STRING("ENTER"), CursorCb_Enter}, + [MENU_NO_ENTRY] = {COMPOUND_STRING("NO ENTRY"), CursorCb_NoEntry}, + [MENU_STORE] = {COMPOUND_STRING("STORE"), CursorCb_Store}, + [MENU_REGISTER] = {gText_Register, CursorCb_Register}, + [MENU_TRADE1] = {sText_Trade4, CursorCb_Trade1}, + [MENU_TRADE2] = {sText_Trade4, CursorCb_Trade2}, + [MENU_TOSS] = {gMenuText_Toss, CursorCb_Toss}, + [MENU_CATALOG_BULB] = {COMPOUND_STRING("Light bulb"), CursorCb_CatalogBulb}, + [MENU_CATALOG_OVEN] = {COMPOUND_STRING("Microwave oven"), CursorCb_CatalogOven}, [MENU_CATALOG_WASHING] = {COMPOUND_STRING("Washing machine"), CursorCb_CatalogWashing}, - [MENU_CATALOG_FRIDGE] = {COMPOUND_STRING("Refrigerator"), CursorCb_CatalogFridge}, - [MENU_CATALOG_FAN] = {COMPOUND_STRING("Electric fan"), CursorCb_CatalogFan}, - [MENU_CATALOG_MOWER] = {COMPOUND_STRING("Lawn mower"), CursorCb_CatalogMower}, - [MENU_CHANGE_FORM] = {COMPOUND_STRING("Change form"), CursorCb_ChangeForm}, - [MENU_CHANGE_ABILITY] = {COMPOUND_STRING("Change Ability"), CursorCb_ChangeAbility}, + [MENU_CATALOG_FRIDGE] = {COMPOUND_STRING("Refrigerator"), CursorCb_CatalogFridge}, + [MENU_CATALOG_FAN] = {COMPOUND_STRING("Electric fan"), CursorCb_CatalogFan}, + [MENU_CATALOG_MOWER] = {COMPOUND_STRING("Lawn mower"), CursorCb_CatalogMower}, + [MENU_CHANGE_FORM] = {COMPOUND_STRING("Change form"), CursorCb_ChangeForm}, + [MENU_CHANGE_ABILITY] = {COMPOUND_STRING("Change Ability"), CursorCb_ChangeAbility}, }; static const u8 sPartyMenuAction_SummarySwitchCancel[] = {MENU_SUMMARY, MENU_SWITCH, MENU_CANCEL1}; @@ -732,7 +734,7 @@ static const u8 sPartyMenuAction_SummaryCancel[] = {MENU_SUMMARY, MENU_CANCEL1}; static const u8 sPartyMenuAction_EnterSummaryCancel[] = {MENU_ENTER, MENU_SUMMARY, MENU_CANCEL1}; 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}; static const u8 sPartyMenuAction_TradeSummaryCancel1[] = {MENU_TRADE1, MENU_SUMMARY, MENU_CANCEL1}; diff --git a/src/party_menu.c b/src/party_menu.c index cb085c5bea..891a9ca041 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -84,6 +84,7 @@ enum { MENU_ITEM, MENU_GIVE, MENU_TAKE_ITEM, + MENU_MOVE_ITEM, MENU_MAIL, MENU_TAKE_MAIL, MENU_READ, @@ -491,6 +492,7 @@ 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); @@ -516,7 +518,7 @@ static bool8 SetUpFieldMove_Surf(void); static bool8 SetUpFieldMove_Fly(void); static bool8 SetUpFieldMove_Waterfall(void); static bool8 SetUpFieldMove_Dive(void); -void TryItemHoldFormChange(struct Pokemon *mon); +void TryItemHoldFormChange(struct Pokemon *mon, s8 slotId); static void ShowMoveSelectWindow(u8 slot); static void Task_HandleWhichMoveInput(u8 taskId); static void Task_HideFollowerNPCForTeleport(u8); @@ -2043,7 +2045,7 @@ static void GiveItemToMon(struct Pokemon *mon, u16 item) itemBytes[0] = item; itemBytes[1] = item >> 8; SetMonData(mon, MON_DATA_HELD_ITEM, itemBytes); - TryItemHoldFormChange(&gPlayerParty[gPartyMenu.slotId]); + TryItemHoldFormChange(&gPlayerParty[gPartyMenu.slotId], gPartyMenu.slotId); } static u8 TryTakeMonItem(struct Pokemon *mon) @@ -2057,7 +2059,7 @@ static u8 TryTakeMonItem(struct Pokemon *mon) item = ITEM_NONE; SetMonData(mon, MON_DATA_HELD_ITEM, &item); - TryItemHoldFormChange(&gPlayerParty[gPartyMenu.slotId]); + TryItemHoldFormChange(&gPlayerParty[gPartyMenu.slotId], gPartyMenu.slotId); return 2; } @@ -6717,7 +6719,7 @@ static void CursorCb_ChangeAbility(u8 taskId) TryMultichoiceFormChange(taskId); } -void TryItemHoldFormChange(struct Pokemon *mon) +void TryItemHoldFormChange(struct Pokemon *mon, s8 slotId) { u32 currentSpecies = GetMonData(mon, MON_DATA_SPECIES); u32 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_ITEM_HOLD, 0); @@ -6725,10 +6727,10 @@ void TryItemHoldFormChange(struct Pokemon *mon) { PlayCry_NormalNoDucking(targetSpecies, 0, CRY_VOLUME_RS, CRY_VOLUME_RS); SetMonData(mon, MON_DATA_SPECIES, &targetSpecies); - FreeAndDestroyMonIconSprite(&gSprites[sPartyMenuBoxes[gPartyMenu.slotId].monSpriteId]); - CreatePartyMonIconSpriteParameterized(targetSpecies, GetMonData(mon, MON_DATA_PERSONALITY, NULL), &sPartyMenuBoxes[gPartyMenu.slotId], 1); + FreeAndDestroyMonIconSprite(&gSprites[sPartyMenuBoxes[slotId].monSpriteId]); + CreatePartyMonIconSpriteParameterized(targetSpecies, GetMonData(mon, MON_DATA_PERSONALITY, NULL), &sPartyMenuBoxes[slotId], 1); CalculateMonStats(mon); - UpdatePartyMonHeldItemSprite(mon, &sPartyMenuBoxes[gPartyMenu.slotId]); + UpdatePartyMonHeldItemSprite(mon, &sPartyMenuBoxes[slotId]); } } @@ -7916,3 +7918,112 @@ void IsLastMonThatKnowsSurf(void) gSpecialVar_Result = !P_CAN_FORGET_HIDDEN_MOVE; } } + +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; + } + + 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); + + TryItemHoldFormChange(&gPlayerParty[gPartyMenu.slotId], gPartyMenu.slotId); + TryItemHoldFormChange(&gPlayerParty[gPartyMenu.slotId2], gPartyMenu.slotId2); + + // 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; + } +} diff --git a/src/strings.c b/src/strings.c index fee143ea68..3d1e1ebf32 100644 --- a/src/strings.c +++ b/src/strings.c @@ -320,6 +320,9 @@ const u8 gText_DoWhatWithMail[] = _("Do what with the MAIL?"); const u8 gText_ChoosePokemonCancel[] = _("Choose POKéMON or CANCEL."); const u8 gText_ChoosePokemonConfirm[] = _("Choose POKéMON and confirm."); const u8 gText_SendWhichMonToPC[] = _("Send which POKéMON to the PC?"); +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}"); const u8 gText_EnjoyCycling[] = _("Let's enjoy cycling!"); const u8 gText_InUseAlready_PM[] = _("This is in use already."); const u8 gText_AlreadyHoldingOne[] = _("{STR_VAR_1} is already holding\none {STR_VAR_2}.");