diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/new_menu_helpers.c | 2 | ||||
-rw-r--r-- | src/party_menu.c | 1455 | ||||
-rw-r--r-- | src/pokemon_icon.c | 2 | ||||
-rw-r--r-- | src/quest_log.c | 12 | ||||
-rw-r--r-- | src/trade.c | 10 |
5 files changed, 1460 insertions, 21 deletions
diff --git a/src/new_menu_helpers.c b/src/new_menu_helpers.c index decd000d6..d2421ed9f 100644 --- a/src/new_menu_helpers.c +++ b/src/new_menu_helpers.c @@ -357,7 +357,7 @@ void SetBgTilemapPalette(u8 bgId, u8 left, u8 top, u8 width, u8 height, u8 palet } } -void CopyRectIntoAltRect(u8 bgId, u16 *dest, u8 left, u8 top, u8 width, u8 height) +void CopyToBufferFromBgTilemap(u8 bgId, u16 *dest, u8 left, u8 top, u8 width, u8 height) { u8 i,j; const u16 *src = GetBgTilemapBuffer(bgId); diff --git a/src/party_menu.c b/src/party_menu.c index 73965c4ae..08600229a 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -27,6 +27,7 @@ #include "item_use.h" #include "link.h" #include "link_rfu.h" +#include "load_save.h" #include "mail.h" #include "mail_data.h" #include "main.h" @@ -43,6 +44,7 @@ #include "pokemon_jump.h" #include "pokemon_storage_system.h" #include "pokemon_summary_screen.h" +#include "quest_log.h" #include "region_map.h" #include "reshow_battle_screen.h" #include "scanline_effect.h" @@ -53,6 +55,7 @@ #include "string_util.h" #include "strings.h" #include "task.h" +#include "teachy_tv.h" #include "text.h" #include "text_window.h" #include "trade.h" @@ -258,11 +261,39 @@ void sub_8120DE0(u8 taskId); void sub_8120E1C(u8 taskId); void sub_8120E58(u8 taskId); void sub_8120EE0(u8 taskId); +void sub_8120FF0(u8 taskId); +void sub_8120FB0(void); bool8 sub_8120F78(u8 taskId); -bool8 sub_81220D4(void); +u8 sub_81220D4(void); void sub_8122084(u8 windowId, const u8 *str); void sub_8122110(u8 windowId); +void sub_812358C(void); void CreateSelectionWindow(void); +bool8 ShouldUseChooseMonText(void); +void UpdatePartyMonHPBar(u8 spriteId, struct Pokemon *mon); +void SpriteCB_UpdatePartyMonIcon(struct Sprite *sprite); +void SpriteCB_BouncePartyMonIcon(struct Sprite *sprite); +void SpriteCB_HeldItem(struct Sprite *sprite); +void UpdatePartyMonHeldItemSprite(struct Pokemon *mon, struct PartyMenuBox *menuBox); +void ShowOrHideHeldItemSprite(u16 item, struct PartyMenuBox *menuBox); +void CreateHeldItemSpriteForTrade(u8 spriteId, bool8 isMail); +void SetPartyMonAilmentGfx(struct Pokemon *mon, struct PartyMenuBox *menuBox); +void UpdatePartyMonAilmentGfx(u8 status, struct PartyMenuBox *menuBox); +void SetPartyMonFieldSelectionActions(struct Pokemon *mons, u8 slotId); +u8 GetPartyMenuActionsTypeInBattle(struct Pokemon *mon); +u8 GetPartySlotEntryStatus(s8 slot); +void Task_HandleSelectionMenuInput(u8 taskId); +void CB2_ShowPokemonSummaryScreen(void); +void CB2_ReturnToPartyMenuFromSummaryScreen(void); +void UpdatePartyToBattleOrder(void); +void SlidePartyMenuBoxOneStep(u8 taskId); +void Task_SlideSelectedSlotsOffscreen(u8 taskId); +void SwitchPartyMon(void); +void Task_SlideSelectedSlotsOnscreen(u8 taskId); +void CB2_WriteMailToGiveMon(void); +void Task_SwitchHoldItemsPrompt(u8 taskId); +void Task_GiveHoldItem(u8 taskId); +void Task_UpdateHeldItemSprite(u8 taskId); EWRAM_DATA struct PartyMenuInternal *sPartyMenuInternal = NULL; EWRAM_DATA struct PartyMenu gPartyMenu = {0}; @@ -1936,24 +1967,1432 @@ void sub_8120EE0(u8 taskId) switch (data[0]) { case 80: - #ifndef NONMATCHING - asm("":::"r5"); - #endif UpdateCurrentPartySelection(&gPartyMenu.slotId, 2); - ++data[0]; break; case 160: PlaySE(SE_SELECT); CreateSelectionWindow(); - ++data[0]; break; case 240: PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[2]); sCursorOptions[sPartyMenuInternal->actions[0]].func(taskId); - // fall through - default: + break; + } + ++data[0]; + } +} + +bool8 sub_8120F78(u8 taskId) +{ + if (JOY_NEW(B_BUTTON)) + { + sPartyMenuInternal->exitCallback = sub_8120FB0; + Task_ClosePartyMenu(taskId); + return TRUE; + } + return FALSE; +} + +void sub_8120FB0(void) +{ + FreeRestoreBattleData(); + LoadPlayerParty(); + SetTeachyTvControllerModeToResume(); + SetMainCallback2(CB2_ReturnToTeachyTV); +} + +void sub_8120FCC(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + data[0] = 0; + gTasks[taskId].func = sub_8120FF0; +} + +void sub_8120FF0(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (!gPaletteFade.active && sub_8120F78(taskId) != TRUE) + { + if (data[0] != 80) + { ++data[0]; + } + else + { + sPartyMenuInternal->exitCallback = CB2_SetUpExitToBattleScreen; + gItemUseCB(taskId, Task_ClosePartyMenuAfterText); + } + } +} + +void InitPartyMenuWindows(u8 layout) +{ + u8 i; + + switch (layout) + { + case PARTY_LAYOUT_SINGLE: + InitWindows(sSinglePartyMenuWindowTemplate); + break; + case PARTY_LAYOUT_DOUBLE: + InitWindows(sDoublePartyMenuWindowTemplate); + break; + case PARTY_LAYOUT_MULTI: + InitWindows(sMultiPartyMenuWindowTemplate); + break; + default: // PARTY_LAYOUT_MULTI_SHOWCASE + InitWindows(sShowcaseMultiPartyMenuWindowTemplate); + break; + } + DeactivateAllTextPrinters(); + for (i = 0; i < PARTY_SIZE; ++i) + FillWindowPixelBuffer(i, PIXEL_FILL(0)); + TextWindow_SetUserSelectedFrame(0, 0x4F, 0xD0); + TextWindow_SetStdFrame0_WithPal(0, 0x58, 0xF0); + LoadPalette(stdpal_get(2), 0xC0, 0x20); + LoadPalette(stdpal_get(0), 0xE0, 0x20); +} + +void CreateCancelConfirmWindows(bool8 chooseHalf) +{ + u8 confirmWindowId; + u8 cancelWindowId; + u8 offset; + + if (gPartyMenu.menuType != PARTY_MENU_TYPE_MULTI_SHOWCASE) + { + if (chooseHalf == TRUE) + { + confirmWindowId = AddWindow(&sConfirmButtonWindowTemplate); + FillWindowPixelBuffer(confirmWindowId, PIXEL_FILL(0)); + AddTextPrinterParameterized4(confirmWindowId, 0, (48 - GetStringWidth(0, gMenuText_Confirm, 0)) / 2u, 1, 0, 0, sFontColorTable[0], -1, gMenuText_Confirm); + PutWindowTilemap(confirmWindowId); + CopyWindowToVram(confirmWindowId, 2); + cancelWindowId = AddWindow(&sMultiCancelButtonWindowTemplate); + offset = 0; + } + else + { + cancelWindowId = AddWindow(&sCancelButtonWindowTemplate); + offset = 3; + } + FillWindowPixelBuffer(cancelWindowId, PIXEL_FILL(0)); + // Branches are functionally identical. Second branch is never reached, Spin Trade wasnt fully implemented + if (gPartyMenu.menuType != PARTY_MENU_TYPE_SPIN_TRADE) + { + offset += (48 - GetStringWidth(0, gFameCheckerText_Cancel, 0)) / 2; + AddTextPrinterParameterized3(cancelWindowId, 0, offset, 1, sFontColorTable[0], -1, gFameCheckerText_Cancel); + } + else + { + offset += (48 - GetStringWidth(0, gOtherText_Exit, 0)) / 2; + AddTextPrinterParameterized3(cancelWindowId, 0, offset, 1, sFontColorTable[0], -1, gOtherText_Exit); + } + PutWindowTilemap(cancelWindowId); + CopyWindowToVram(cancelWindowId, 2); + ScheduleBgCopyTilemapToVram(0); + } +} + +u16 *GetPartyMenuPalBufferPtr(u8 paletteId) +{ + return &sPartyMenuInternal->palBuffer[paletteId]; +} + +void BlitBitmapToPartyWindow(u8 windowId, const u8 *b, u8 c, u8 x, u8 y, u8 width, u8 height) +{ + u8 *pixels = AllocZeroed(height * width * 32); + u8 i, j; + + if (pixels != NULL) + { + for (i = 0; i < height; ++i) + for (j = 0; j < width; ++j) + CpuCopy16(GetPartyMenuBgTile(b[x + j + ((y + i) * c)]), &pixels[(i * width + j) * 32], 32); + BlitBitmapToWindow(windowId, pixels, x * 8, y * 8, width * 8, height * 8); + Free(pixels); + } +} + +void BlitBitmapToPartyWindow_LeftColumn(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 isEgg) +{ + if (width == 0 && height == 0) + { + width = 10; + height = 7; + } + if (!isEgg) + BlitBitmapToPartyWindow(windowId, sMainSlotTileNums, 10, x, y, width, height); + else + BlitBitmapToPartyWindow(windowId, sMainSlotTileNums_Egg, 10, x, y, width, height); +} + +void BlitBitmapToPartyWindow_RightColumn(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 isEgg) +{ + if (width == 0 && height == 0) + { + width = 18; + height = 3; + } + if (!isEgg) + BlitBitmapToPartyWindow(windowId, sOtherSlotsTileNums, 18, x, y, width, height); + else + BlitBitmapToPartyWindow(windowId, sOtherSlotsTileNums_Egg, 18, x, y, width, height); +} + +void DrawEmptySlot(u8 windowId) +{ + BlitBitmapToPartyWindow(windowId, sEmptySlotTileNums, 18, 0, 0, 18, 3); +} + +#define LOAD_PARTY_BOX_PAL(paletteIds, paletteOffsets) \ +{ \ + LoadPalette(GetPartyMenuPalBufferPtr(paletteIds[0]), paletteOffsets[0] + palNum, 2); \ + LoadPalette(GetPartyMenuPalBufferPtr(paletteIds[1]), paletteOffsets[1] + palNum, 2); \ + LoadPalette(GetPartyMenuPalBufferPtr(paletteIds[2]), paletteOffsets[2] + palNum, 2); \ +} + +void LoadPartyBoxPalette(struct PartyMenuBox *menuBox, u8 palFlags) +{ + u8 palNum = GetWindowAttribute(menuBox->windowId, WINDOW_PALETTE_NUM) * 16; + + if (palFlags & PARTY_PAL_TO_SOFTBOIL) + { + if (palFlags & PARTY_PAL_SELECTED) + { + LOAD_PARTY_BOX_PAL(sPartyBoxSelectedForActionPalIds1, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxCurrSelectionPalIds2, sPartyBoxPalOffsets2); + } + else + { + LOAD_PARTY_BOX_PAL(sPartyBoxSelectedForActionPalIds1, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxSelectedForActionPalIds2, sPartyBoxPalOffsets2); + } + } + else if (palFlags & PARTY_PAL_SWITCHING) + { + LOAD_PARTY_BOX_PAL(sPartyBoxSelectedForActionPalIds1, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxSelectedForActionPalIds2, sPartyBoxPalOffsets2); + } + else if (palFlags & PARTY_PAL_TO_SWITCH) + { + if (palFlags & PARTY_PAL_SELECTED) + { + LOAD_PARTY_BOX_PAL(sPartyBoxSelectedForActionPalIds1, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxCurrSelectionPalIds2, sPartyBoxPalOffsets2); + } + else + { + LOAD_PARTY_BOX_PAL(sPartyBoxSelectedForActionPalIds1, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxSelectedForActionPalIds2, sPartyBoxPalOffsets2); + } + } + else if (palFlags & PARTY_PAL_FAINTED) + { + if (palFlags & PARTY_PAL_SELECTED) + { + LOAD_PARTY_BOX_PAL(sPartyBoxCurrSelectionFaintedPalIds, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxCurrSelectionPalIds2, sPartyBoxPalOffsets2); + } + else + { + LOAD_PARTY_BOX_PAL(sPartyBoxFaintedPalIds1, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxFaintedPalIds2, sPartyBoxPalOffsets2); + } + } + else if (palFlags & PARTY_PAL_MULTI_ALT) + { + if (palFlags & PARTY_PAL_SELECTED) + { + LOAD_PARTY_BOX_PAL(sPartyBoxCurrSelectionMultiPalIds, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxCurrSelectionPalIds2, sPartyBoxPalOffsets2); + } + else + { + LOAD_PARTY_BOX_PAL(sPartyBoxMultiPalIds1, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxMultiPalIds2, sPartyBoxPalOffsets2); + } + } + else if (palFlags & PARTY_PAL_SELECTED) + { + LOAD_PARTY_BOX_PAL(sPartyBoxCurrSelectionPalIds1, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxCurrSelectionPalIds2, sPartyBoxPalOffsets2); + } + else + { + LOAD_PARTY_BOX_PAL(sPartyBoxEmptySlotPalIds1, sPartyBoxPalOffsets1); + LOAD_PARTY_BOX_PAL(sPartyBoxEmptySlotPalIds2, sPartyBoxPalOffsets2); + } +} + +void DisplayPartyPokemonBarDetail(u8 windowId, const u8 *str, u8 color, const u8 *align) +{ + AddTextPrinterParameterized3(windowId, 0, align[0], align[1], sFontColorTable[color], 0, str); +} + +void DisplayPartyPokemonNickname(struct Pokemon *mon, struct PartyMenuBox *menuBox, u8 c) +{ + u8 nickname[POKEMON_NAME_LENGTH + 1]; + + if (GetMonData(mon, MON_DATA_SPECIES) != SPECIES_NONE) + { + if (c == 1) + menuBox->infoRects->blitFunc(menuBox->windowId, menuBox->infoRects->dimensions[0] >> 3, menuBox->infoRects->dimensions[1] >> 3, menuBox->infoRects->dimensions[2] >> 3, menuBox->infoRects->dimensions[3] >> 3, FALSE); + GetMonNickname(mon, nickname); + DisplayPartyPokemonBarDetail(menuBox->windowId, nickname, 0, menuBox->infoRects->dimensions); + } +} + +void DisplayPartyPokemonLevelCheck(struct Pokemon *mon, struct PartyMenuBox *menuBox, u8 c) +{ + if (GetMonData(mon, MON_DATA_SPECIES) != SPECIES_NONE) + { + u8 ailment = GetMonAilment(mon); + + if (ailment == AILMENT_NONE || ailment == AILMENT_PKRS) + { + if (c != 0) + menuBox->infoRects->blitFunc(menuBox->windowId, menuBox->infoRects->dimensions[4] >> 3, (menuBox->infoRects->dimensions[5] >> 3) + 1, menuBox->infoRects->dimensions[6] >> 3, menuBox->infoRects->dimensions[7] >> 3, FALSE); + if (c != 2) + DisplayPartyPokemonLevel(GetMonData(mon, MON_DATA_LEVEL), menuBox); + } + } +} + +void DisplayPartyPokemonLevel(u8 level, struct PartyMenuBox *menuBox) +{ + ConvertIntToDecimalStringN(gStringVar2, level, STR_CONV_MODE_LEFT_ALIGN, 3); + StringCopy(gStringVar1, gText_Lv); + StringAppend(gStringVar1, gStringVar2); + DisplayPartyPokemonBarDetail(menuBox->windowId, gStringVar1, 0, &menuBox->infoRects->dimensions[4]); +} + +void DisplayPartyPokemonGenderNidoranCheck(struct Pokemon *mon, struct PartyMenuBox *menuBox, u8 c) +{ + u8 nickname[POKEMON_NAME_LENGTH + 1]; + + if (c == 1) + menuBox->infoRects->blitFunc(menuBox->windowId, menuBox->infoRects->dimensions[8] >> 3, (menuBox->infoRects->dimensions[9] >> 3) + 1, menuBox->infoRects->dimensions[10] >> 3, menuBox->infoRects->dimensions[11] >> 3, FALSE); + GetMonNickname(mon, nickname); + DisplayPartyPokemonGender(GetMonGender(mon), GetMonData(mon, MON_DATA_SPECIES), nickname, menuBox); +} + +void DisplayPartyPokemonGender(u8 gender, u16 species, u8 *nickname, struct PartyMenuBox *menuBox) +{ + u8 palNum = GetWindowAttribute(menuBox->windowId, WINDOW_PALETTE_NUM) * 16; + + if (species == SPECIES_NONE) + return; + if ((species == SPECIES_NIDORAN_M || species == SPECIES_NIDORAN_F) && StringCompare(nickname, gSpeciesNames[species]) == 0) + return; + switch (gender) + { + case MON_MALE: + LoadPalette(GetPartyMenuPalBufferPtr(sGenderMalePalIds[0]), sGenderPalOffsets[0] + palNum, 2); + LoadPalette(GetPartyMenuPalBufferPtr(sGenderMalePalIds[1]), sGenderPalOffsets[1] + palNum, 2); + DisplayPartyPokemonBarDetail(menuBox->windowId, gText_MaleSymbol, 2, &menuBox->infoRects->dimensions[8]); + break; + case MON_FEMALE: + LoadPalette(GetPartyMenuPalBufferPtr(sGenderFemalePalIds[0]), sGenderPalOffsets[0] + palNum, 2); + LoadPalette(GetPartyMenuPalBufferPtr(sGenderFemalePalIds[1]), sGenderPalOffsets[1] + palNum, 2); + DisplayPartyPokemonBarDetail(menuBox->windowId, gText_FemaleSymbol, 2, &menuBox->infoRects->dimensions[8]); + break; + } +} + +void DisplayPartyPokemonHPCheck(struct Pokemon *mon, struct PartyMenuBox *menuBox, u8 c) +{ + if (GetMonData(mon, MON_DATA_SPECIES) != SPECIES_NONE) + { + if (c != 0) + menuBox->infoRects->blitFunc(menuBox->windowId, menuBox->infoRects->dimensions[12] >> 3, (menuBox->infoRects->dimensions[13] >> 3) + 1, menuBox->infoRects->dimensions[14] >> 3, menuBox->infoRects->dimensions[15] >> 3, FALSE); + if (c != 2) + DisplayPartyPokemonHP(GetMonData(mon, MON_DATA_HP), menuBox); + } +} + +void DisplayPartyPokemonHP(u16 hp, struct PartyMenuBox *menuBox) +{ + u8 *strOut = ConvertIntToDecimalStringN(gStringVar1, hp, STR_CONV_MODE_RIGHT_ALIGN, 3); + + strOut[0] = CHAR_SLASH; + strOut[1] = EOS; + DisplayPartyPokemonBarDetail(menuBox->windowId, gStringVar1, 0, &menuBox->infoRects->dimensions[12]); +} + +void DisplayPartyPokemonMaxHPCheck(struct Pokemon *mon, struct PartyMenuBox *menuBox, u8 c) +{ + if (GetMonData(mon, MON_DATA_SPECIES) != SPECIES_NONE) + { + if (c != 0) + menuBox->infoRects->blitFunc(menuBox->windowId, (menuBox->infoRects->dimensions[16] >> 3) + 1, (menuBox->infoRects->dimensions[17] >> 3) + 1, menuBox->infoRects->dimensions[18] >> 3, menuBox->infoRects->dimensions[19] >> 3, FALSE); + if (c != 2) + DisplayPartyPokemonMaxHP(GetMonData(mon, MON_DATA_MAX_HP), menuBox); + } +} + +void DisplayPartyPokemonMaxHP(u16 maxhp, struct PartyMenuBox *menuBox) +{ + ConvertIntToDecimalStringN(gStringVar2, maxhp, STR_CONV_MODE_RIGHT_ALIGN, 3); + StringCopy(gStringVar1, gText_Slash); + StringAppend(gStringVar1, gStringVar2); + DisplayPartyPokemonBarDetail(menuBox->windowId, gStringVar1, 0, &menuBox->infoRects->dimensions[16]); +} + +void DisplayPartyPokemonHPBarCheck(struct Pokemon *mon, struct PartyMenuBox *menuBox) +{ + if (GetMonData(mon, MON_DATA_SPECIES) != SPECIES_NONE) + DisplayPartyPokemonHPBar(GetMonData(mon, MON_DATA_HP), GetMonData(mon, MON_DATA_MAX_HP), menuBox); +} + +void DisplayPartyPokemonHPBar(u16 hp, u16 maxhp, struct PartyMenuBox *menuBox) +{ + u8 palNum = GetWindowAttribute(menuBox->windowId, WINDOW_PALETTE_NUM) * 16; + u8 hpFraction; + + switch (GetHPBarLevel(hp, maxhp)) + { + case HP_BAR_GREEN: + case HP_BAR_FULL: + LoadPalette(GetPartyMenuPalBufferPtr(sHPBarGreenPalIds[0]), sHPBarPalOffsets[0] + palNum, 2); + LoadPalette(GetPartyMenuPalBufferPtr(sHPBarGreenPalIds[1]), sHPBarPalOffsets[1] + palNum, 2); + break; + case HP_BAR_YELLOW: + LoadPalette(GetPartyMenuPalBufferPtr(sHPBarYellowPalIds[0]), sHPBarPalOffsets[0] + palNum, 2); + LoadPalette(GetPartyMenuPalBufferPtr(sHPBarYellowPalIds[1]), sHPBarPalOffsets[1] + palNum, 2); + break; + default: + LoadPalette(GetPartyMenuPalBufferPtr(sHPBarRedPalIds[0]), sHPBarPalOffsets[0] + palNum, 2); + LoadPalette(GetPartyMenuPalBufferPtr(sHPBarRedPalIds[1]), sHPBarPalOffsets[1] + palNum, 2); + break; + } + hpFraction = GetScaledHPFraction(hp, maxhp, menuBox->infoRects->dimensions[22]); + FillWindowPixelRect(menuBox->windowId, sHPBarPalOffsets[1], menuBox->infoRects->dimensions[20], menuBox->infoRects->dimensions[21], hpFraction, 1); + FillWindowPixelRect(menuBox->windowId, sHPBarPalOffsets[0], menuBox->infoRects->dimensions[20], menuBox->infoRects->dimensions[21] + 1, hpFraction, 2); + if (hpFraction != menuBox->infoRects->dimensions[22]) + { + // This appears to be an alternating fill + FillWindowPixelRect(menuBox->windowId, 0x0D, menuBox->infoRects->dimensions[20] + hpFraction, menuBox->infoRects->dimensions[21], menuBox->infoRects->dimensions[22] - hpFraction, 1); + FillWindowPixelRect(menuBox->windowId, 0x02, menuBox->infoRects->dimensions[20] + hpFraction, menuBox->infoRects->dimensions[21] + 1, menuBox->infoRects->dimensions[22] - hpFraction, 2); + } + CopyWindowToVram(menuBox->windowId, 2); +} + +void DisplayPartyPokemonDescriptionText(u8 stringId, struct PartyMenuBox *menuBox, u8 c) +{ + if (c != 0) + menuBox->infoRects->blitFunc(menuBox->windowId, menuBox->infoRects->descTextLeft >> 3, menuBox->infoRects->descTextTop >> 3, menuBox->infoRects->descTextWidth >> 3, menuBox->infoRects->descTextHeight >> 3, TRUE); + if (c != 2) + AddTextPrinterParameterized3(menuBox->windowId, 1, menuBox->infoRects->descTextLeft, menuBox->infoRects->descTextTop, sFontColorTable[0], 0, sDescriptionStringTable[stringId]); +} + +void PartyMenuRemoveWindow(u8 *ptr) +{ + if (*ptr != 0xFF) + { + ClearStdWindowAndFrameToTransparent(*ptr, 0); + RemoveWindow(*ptr); + *ptr = 0xFF; + ScheduleBgCopyTilemapToVram(2); + } +} + +void DisplayPartyMenuStdMessage(u32 stringId) +{ + u8 *windowPtr = &sPartyMenuInternal->windowId[1]; + + if (*windowPtr != 0xFF) + PartyMenuRemoveWindow(windowPtr); + + if (stringId != PARTY_MSG_NONE) + { + switch (stringId) + { + case PARTY_MSG_DO_WHAT_WITH_MON: + *windowPtr = AddWindow(&sDoWhatWithMonMsgWindowTemplate); + break; + case PARTY_MSG_DO_WHAT_WITH_ITEM: + *windowPtr = AddWindow(&sDoWhatWithItemMsgWindowTemplate); + break; + case PARTY_MSG_DO_WHAT_WITH_MAIL: + *windowPtr = AddWindow(&sDoWhatWithMailMsgWindowTemplate); + break; + case PARTY_MSG_RESTORE_WHICH_MOVE: + case PARTY_MSG_BOOST_PP_WHICH_MOVE: + *windowPtr = AddWindow(&sWhichMoveMsgWindowTemplate); + break; + default: + *windowPtr = AddWindow(&sDefaultPartyMsgWindowTemplate); + break; + } + + if (stringId == PARTY_MSG_CHOOSE_MON) + { + if (sPartyMenuInternal->chooseHalf) + stringId = PARTY_MSG_CHOOSE_MON_AND_CONFIRM; + else if (!ShouldUseChooseMonText()) + stringId = PARTY_MSG_CHOOSE_MON_OR_CANCEL; + } + DrawStdFrameWithCustomTileAndPalette(*windowPtr, FALSE, 0x58, 0xF); + StringExpandPlaceholders(gStringVar4, sActionStringTable[stringId]); + AddTextPrinterParameterized(*windowPtr, 2, gStringVar4, 0, 2, 0, 0); + ScheduleBgCopyTilemapToVram(2); + } +} + +bool8 ShouldUseChooseMonText(void) +{ + struct Pokemon *party = gPlayerParty; + u8 i; + u8 numAliveMons = 0; + + if (gPartyMenu.action == PARTY_ACTION_SEND_OUT) + return TRUE; + for (i = 0; i < PARTY_SIZE; ++i) + { + if (GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE && (GetMonData(&party[i], MON_DATA_HP) != 0 || GetMonData(&party[i], MON_DATA_IS_EGG))) + ++numAliveMons; + if (numAliveMons > 1) + return TRUE; + } + return FALSE; +} + +u8 DisplaySelectionWindow(u8 windowType) +{ + struct WindowTemplate window; + u8 cursorDimension; + u8 fontAttribute; + u8 i; + + switch (windowType) + { + case SELECTWINDOW_ACTIONS: + window = SetWindowTemplateFields(2, 19, 19 - (sPartyMenuInternal->numActions * 2), 10, sPartyMenuInternal->numActions * 2, 14, 0x2BF); + break; + case SELECTWINDOW_ITEM: + window = sItemGiveTakeWindowTemplate; + break; + case SELECTWINDOW_MAIL: + window = sMailReadTakeWindowTemplate; + break; + default: // SELECTWINDOW_MOVES + window = sMoveSelectWindowTemplate; + break; + } + sPartyMenuInternal->windowId[0] = AddWindow(&window); + DrawStdFrameWithCustomTileAndPalette(sPartyMenuInternal->windowId[0], FALSE, 0x4F, 13); + if (windowType == SELECTWINDOW_MOVES) + return sPartyMenuInternal->windowId[0]; + cursorDimension = GetMenuCursorDimensionByFont(2, 0); + fontAttribute = GetFontAttribute(2, FONTATTR_LETTER_SPACING); + for (i = 0; i < sPartyMenuInternal->numActions; ++i) + { + u8 fontColorsId = (sPartyMenuInternal->actions[i] >= MENU_FIELD_MOVES) ? 4 : 3; + + AddTextPrinterParameterized4(sPartyMenuInternal->windowId[0], 2, cursorDimension, (i * 16) + 2, fontAttribute, 0, sFontColorTable[fontColorsId], 0, sCursorOptions[sPartyMenuInternal->actions[i]].text); + } + Menu_InitCursorInternal(sPartyMenuInternal->windowId[0], 2, 0, 2, 16, sPartyMenuInternal->numActions, 0, 1); + ScheduleBgCopyTilemapToVram(2); + return sPartyMenuInternal->windowId[0]; +} + +void PartyMenuPrintText(const u8 *text) +{ + DrawStdFrameWithCustomTileAndPalette(6, FALSE, 0x4F, 13); + gTextFlags.canABSpeedUpPrint = TRUE; + AddTextPrinterParameterized2(6, 2, text, GetTextSpeedSetting(), 0, 2, 1, 3); +} + +void PartyMenuDisplayYesNoMenu(void) +{ + CreateYesNoMenu(&sPartyMenuYesNoWindowTemplate, 2, 0, 2, 0x4F, 13, 0); +} + +u8 CreateLevelUpStatsWindow(void) +{ + sPartyMenuInternal->windowId[0] = AddWindow(&sLevelUpStatsWindowTemplate); + DrawStdFrameWithCustomTileAndPalette(sPartyMenuInternal->windowId[0], FALSE, 0x4F, 13); + return sPartyMenuInternal->windowId[0]; +} + +void RemoveLevelUpStatsWindow(void) +{ + ClearWindowTilemap(sPartyMenuInternal->windowId[0]); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]); +} + +void sub_8122084(u8 windowId, const u8 *str) +{ + StringExpandPlaceholders(gStringVar4, str); + gTextFlags.canABSpeedUpPrint = TRUE; + AddTextPrinterParameterized2(windowId, 4, gStringVar4, GetTextSpeedSetting(), 0, 2, 1, 3); +} + +bool8 sub_81220D4(void) +{ + u8 windowId = AddWindow(&gUnknown_845A170); + + TextWindow_LoadResourcesStdFrame0(windowId, 0x4F, 0xE0); + DrawDialogFrameWithCustomTileAndPalette(windowId, 1, 0x4F, 0xE); + sub_8122084(windowId, gUnknown_8417457); + return windowId; +} + +void sub_8122110(u8 windowId) +{ + ClearWindowTilemap(windowId); + ClearDialogWindowAndFrameToTransparent(windowId, FALSE); + RemoveWindow(windowId); + ScheduleBgCopyTilemapToVram(2); +} + +void sub_8122138(u8 action) +{ + u8 attr; + struct PartyMenuInternal *ptr = sPartyMenuInternal; + + if (action <= 17) + { + if (ptr->windowId[2] != 0xFF) + { + ClearWindowTilemap(ptr->windowId[2]); + RemoveWindow(ptr->windowId[2]); + ptr->windowId[2] = 0xFF; + ScheduleBgCopyTilemapToVram(2); + } + } + else + { + if (ptr->windowId[2] == 0xFF) + ptr->windowId[2] = AddWindow(&gUnknown_845A178); + sub_8112F18(ptr->windowId[2]); + attr = GetFontAttribute(2, FONTATTR_LETTER_SPACING); + AddTextPrinterParameterized4(ptr->windowId[2], 2, 3, 6, attr, 0, sFontColorTable[5], 0, sHMDescriptionTable[action - 18]); + PutWindowTilemap(ptr->windowId[2]); + ScheduleBgCopyTilemapToVram(2); + } +} + +void CreatePartyMonIconSprite(struct Pokemon *mon, struct PartyMenuBox *menuBox, u32 slot) +{ + bool32 handleDeoxys = TRUE; + u16 species2; + + // If in a multi battle, show partners Deoxys icon as Normal forme + if (IsMultiBattle() == TRUE && gMain.inBattle) + handleDeoxys = (sMultiBattlePartnersPartyMask[slot] ^ handleDeoxys) ? TRUE : FALSE; + species2 = GetMonData(mon, MON_DATA_SPECIES2); + CreatePartyMonIconSpriteParameterized(species2, GetMonData(mon, MON_DATA_PERSONALITY), menuBox, 1, handleDeoxys); + UpdatePartyMonHPBar(menuBox->monSpriteId, mon); +} + +void CreatePartyMonIconSpriteParameterized(u16 species, u32 pid, struct PartyMenuBox *menuBox, u8 priority, bool32 handleDeoxys) +{ + if (species != SPECIES_NONE) + { + menuBox->monSpriteId = CreateMonIcon(species, SpriteCB_MonIcon, menuBox->spriteCoords[0], menuBox->spriteCoords[1], 4, pid, handleDeoxys); + gSprites[menuBox->monSpriteId].oam.priority = priority; + } +} + +void UpdateHPBar(u8 spriteId, u16 hp, u16 maxhp) +{ + switch (GetHPBarLevel(hp, maxhp)) + { + case HP_BAR_FULL: + SetPartyHPBarSprite(&gSprites[spriteId], 0); + break; + case HP_BAR_GREEN: + SetPartyHPBarSprite(&gSprites[spriteId], 1); + break; + case HP_BAR_YELLOW: + SetPartyHPBarSprite(&gSprites[spriteId], 2); + break; + case HP_BAR_RED: + SetPartyHPBarSprite(&gSprites[spriteId], 3); + break; + default: + SetPartyHPBarSprite(&gSprites[spriteId], 4); + break; + } +} + +void UpdatePartyMonHPBar(u8 spriteId, struct Pokemon *mon) +{ + UpdateHPBar(spriteId, GetMonData(mon, MON_DATA_HP), GetMonData(mon, MON_DATA_MAX_HP)); +} + +void AnimateSelectedPartyIcon(u8 spriteId, u8 animNum) +{ + gSprites[spriteId].data[0] = 0; + if (animNum == 0) + { + if (gSprites[spriteId].pos1.x == 16) + { + gSprites[spriteId].pos2.x = 0; + gSprites[spriteId].pos2.y = -4; + } + else + { + gSprites[spriteId].pos2.x = -4; + gSprites[spriteId].pos2.y = 0; + } + gSprites[spriteId].callback = SpriteCB_UpdatePartyMonIcon; + } + else + { + gSprites[spriteId].pos2.x = 0; + gSprites[spriteId].pos2.y = 0; + gSprites[spriteId].callback = SpriteCB_BouncePartyMonIcon; + } +} + +void SpriteCB_BouncePartyMonIcon(struct Sprite *sprite) +{ + u8 animCmd = UpdateMonIconFrame(sprite); + + if (animCmd != 0) + { + if (animCmd & 1) // % 2 also matches + sprite->pos2.y = -3; + else + sprite->pos2.y = 1; + } +} + +void SpriteCB_UpdatePartyMonIcon(struct Sprite *sprite) +{ + UpdateMonIconFrame(sprite); +} + +void CreatePartyMonHeldItemSprite(struct Pokemon *mon, struct PartyMenuBox *menuBox) +{ + if (GetMonData(mon, MON_DATA_SPECIES) != SPECIES_NONE) + { + menuBox->itemSpriteId = CreateSprite(&sSpriteTemplate_HeldItem, menuBox->spriteCoords[2], menuBox->spriteCoords[3], 0); + UpdatePartyMonHeldItemSprite(mon, menuBox); + } +} + +void CreatePartyMonHeldItemSpriteParameterized(u16 species, u16 item, struct PartyMenuBox *menuBox) +{ + if (species != SPECIES_NONE) + { + menuBox->itemSpriteId = CreateSprite(&sSpriteTemplate_HeldItem, menuBox->spriteCoords[2], menuBox->spriteCoords[3], 0); + gSprites[menuBox->itemSpriteId].oam.priority = 0; + ShowOrHideHeldItemSprite(item, menuBox); + } +} + +void UpdatePartyMonHeldItemSprite(struct Pokemon *mon, struct PartyMenuBox *menuBox) +{ + ShowOrHideHeldItemSprite(GetMonData(mon, MON_DATA_HELD_ITEM), menuBox); +} + +void ShowOrHideHeldItemSprite(u16 item, struct PartyMenuBox *menuBox) +{ + if (item == ITEM_NONE) + { + gSprites[menuBox->itemSpriteId].invisible = TRUE; + } + else + { + if (ItemIsMail(item)) + StartSpriteAnim(&gSprites[menuBox->itemSpriteId], 1); + else + StartSpriteAnim(&gSprites[menuBox->itemSpriteId], 0); + gSprites[menuBox->itemSpriteId].invisible = FALSE; + } +} + +void LoadHeldItemIcons(void) +{ + LoadSpriteSheet(&sSpriteSheet_HeldItem); + LoadSpritePalette(&sSpritePalette_HeldItem); +} + +void DrawHeldItemIconsForTrade(u8 *partyCounts, u8 *partySpriteIds, u8 whichParty) +{ + u16 i; + u16 item; + + switch (whichParty) + { + case TRADE_PLAYER: + for (i = 0; i < partyCounts[TRADE_PLAYER]; ++i) + { + item = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + if (item != ITEM_NONE) + CreateHeldItemSpriteForTrade(partySpriteIds[i], ItemIsMail(item)); + } + break; + case TRADE_PARTNER: + for (i = 0; i < partyCounts[TRADE_PARTNER]; ++i) + { + item = GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM); + if (item != ITEM_NONE) + CreateHeldItemSpriteForTrade(partySpriteIds[i + PARTY_SIZE], ItemIsMail(item)); + } + break; + } +} + +void CreateHeldItemSpriteForTrade(u8 spriteId, bool8 isMail) +{ + u8 subpriority = gSprites[spriteId].subpriority; + u8 newSpriteId = CreateSprite(&sSpriteTemplate_HeldItem, 250, 170, subpriority - 1); + + gSprites[newSpriteId].pos2.x = 4; + gSprites[newSpriteId].pos2.y = 10; + gSprites[newSpriteId].callback = SpriteCB_HeldItem; + gSprites[newSpriteId].data[7] = spriteId; + StartSpriteAnim(&gSprites[newSpriteId], isMail); + gSprites[newSpriteId].callback(&gSprites[newSpriteId]); +} + +void SpriteCB_HeldItem(struct Sprite *sprite) +{ + u8 otherSpriteId = sprite->data[7]; + + if (gSprites[otherSpriteId].invisible) + { + sprite->invisible = TRUE; + } + else + { + sprite->invisible = FALSE; + sprite->pos1.x = gSprites[otherSpriteId].pos1.x + gSprites[otherSpriteId].pos2.x; + sprite->pos1.y = gSprites[otherSpriteId].pos1.y + gSprites[otherSpriteId].pos2.y; + } +} + +void CreatePartyMonPokeballSprite(struct Pokemon *mon, struct PartyMenuBox *menuBox) +{ + if (GetMonData(mon, MON_DATA_SPECIES) != SPECIES_NONE) + menuBox->pokeballSpriteId = CreateSprite(&sSpriteTemplate_MenuPokeball, menuBox->spriteCoords[6], menuBox->spriteCoords[7], 8); +} + +void CreatePartyMonPokeballSpriteParameterized(u16 species, struct PartyMenuBox *menuBox) +{ + if (species != SPECIES_NONE) + { + menuBox->pokeballSpriteId = CreateSprite(&sSpriteTemplate_MenuPokeball, menuBox->spriteCoords[6], menuBox->spriteCoords[7], 8); + gSprites[menuBox->pokeballSpriteId].oam.priority = 0; + } +} + +// For Cancel when Confirm isnt present +u8 CreatePokeballButtonSprite(u8 x, u8 y) +{ + u8 spriteId = CreateSprite(&sSpriteTemplate_MenuPokeball, x, y, 8); + + gSprites[spriteId].oam.priority = 2; + return spriteId; +} + +// For Confirm and Cancel when both are present +u8 CreateSmallPokeballButtonSprite(u8 x, u8 y) +{ + return CreateSprite(&sSpriteTemplate_MenuPokeballSmall, x, y, 8); +} + +void PartyMenuStartSpriteAnim(u8 spriteId, u8 animNum) +{ + StartSpriteAnim(&gSprites[spriteId], animNum); +} + +// Unused. Might explain the large blank section in gPartyMenuPokeballSmall_Gfx +// At the very least this is how the unused anim cmds for sSpriteAnimTable_MenuPokeballSmall were meant to be accessed +void SpriteCB_BounceConfirmCancelButton(u8 spriteId, u8 spriteId2, u8 animNum) +{ + if (animNum == 0) + { + StartSpriteAnim(&gSprites[spriteId], 2); + StartSpriteAnim(&gSprites[spriteId2], 4); + gSprites[spriteId].pos2.y = 0; + gSprites[spriteId2].pos2.y = 0; + } + else + { + StartSpriteAnim(&gSprites[spriteId], 3); + StartSpriteAnim(&gSprites[spriteId2], 5); + gSprites[spriteId].pos2.y = -4; + gSprites[spriteId2].pos2.y = 4; + } +} + +void LoadPartyMenuPokeballGfx(void) +{ + LoadCompressedSpriteSheet(&sSpriteSheet_MenuPokeball); + LoadCompressedSpriteSheet(&sSpriteSheet_MenuPokeballSmall); + LoadCompressedSpritePalette(&sSpritePalette_MenuPokeball); +} + +void CreatePartyMonStatusSprite(struct Pokemon *mon, struct PartyMenuBox *menuBox) +{ + if (GetMonData(mon, MON_DATA_SPECIES) != SPECIES_NONE) + { + menuBox->statusSpriteId = CreateSprite(&sSpriteTemplate_StatusIcons, menuBox->spriteCoords[4], menuBox->spriteCoords[5], 0); + SetPartyMonAilmentGfx(mon, menuBox); + } +} + +void CreatePartyMonStatusSpriteParameterized(u16 species, u8 status, struct PartyMenuBox *menuBox) +{ + if (species != SPECIES_NONE) + { + menuBox->statusSpriteId = CreateSprite(&sSpriteTemplate_StatusIcons, menuBox->spriteCoords[4], menuBox->spriteCoords[5], 0); + UpdatePartyMonAilmentGfx(status, menuBox); + gSprites[menuBox->statusSpriteId].oam.priority = 0; + } +} + +void SetPartyMonAilmentGfx(struct Pokemon *mon, struct PartyMenuBox *menuBox) +{ + UpdatePartyMonAilmentGfx(GetMonAilment(mon), menuBox); +} + +void UpdatePartyMonAilmentGfx(u8 status, struct PartyMenuBox *menuBox) +{ + switch (status) + { + case AILMENT_NONE: + case AILMENT_PKRS: + gSprites[menuBox->statusSpriteId].invisible = TRUE; + break; + default: + StartSpriteAnim(&gSprites[menuBox->statusSpriteId], status - 1); + gSprites[menuBox->statusSpriteId].invisible = FALSE; + break; + } +} + +void LoadPartyMenuAilmentGfx(void) +{ + LoadCompressedSpriteSheet(&sSpriteSheet_StatusIcons); + LoadCompressedSpritePalette(&sSpritePalette_StatusIcons); +} + +void SetPartyMonSelectionActions(struct Pokemon *mons, u8 slotId, u8 action) +{ + u8 i; + + if (action == ACTIONS_NONE) + { + SetPartyMonFieldSelectionActions(mons, slotId); + } + else + { + sPartyMenuInternal->numActions = sPartyMenuActionCounts[action]; + for (i = 0; i < sPartyMenuInternal->numActions; ++i) + sPartyMenuInternal->actions[i] = sPartyMenuActions[action][i]; + } +} + +void SetPartyMonFieldSelectionActions(struct Pokemon *mons, u8 slotId) +{ + u8 i, j; + + sPartyMenuInternal->numActions = 0; + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_SUMMARY); + // Add field moves to action list + for (i = 0; i < MAX_MON_MOVES; ++i) + { + for (j = 0; sFieldMoves[j] != FIELD_MOVE_END; ++j) + { + if (GetMonData(&mons[slotId], i + MON_DATA_MOVE1) == sFieldMoves[j]) + { + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, j + MENU_FIELD_MOVES); + break; + } + } + } + if (GetMonData(&mons[1], MON_DATA_SPECIES) != SPECIES_NONE) + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_SWITCH); + if (ItemIsMail(GetMonData(&mons[slotId], MON_DATA_HELD_ITEM))) + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_MAIL); + else + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_ITEM); + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_CANCEL1); +} + +u8 GetPartyMenuActionsType(struct Pokemon *mon) +{ + u32 actionType; + + switch (gPartyMenu.menuType) + { + case PARTY_MENU_TYPE_FIELD: + if (GetMonData(mon, MON_DATA_IS_EGG)) + actionType = ACTIONS_SWITCH; + else + actionType = ACTIONS_NONE; // actions populated by SetPartyMonFieldSelectionActions + break; + case PARTY_MENU_TYPE_IN_BATTLE: + actionType = GetPartyMenuActionsTypeInBattle(mon); + break; + case PARTY_MENU_TYPE_CHOOSE_HALF: + switch (GetPartySlotEntryStatus(gPartyMenu.slotId)) + { + default: // Not eligible + actionType = ACTIONS_SUMMARY_ONLY; + break; + case 0: // Eligible + actionType = ACTIONS_ENTER; + break; + case 1: // Already selected + actionType = ACTIONS_NO_ENTRY; break; } + break; + case PARTY_MENU_TYPE_DAYCARE: + actionType = (GetMonData(mon, MON_DATA_IS_EGG)) ? ACTIONS_SUMMARY_ONLY : ACTIONS_STORE; + break; + case PARTY_MENU_TYPE_UNION_ROOM_REGISTER: + actionType = ACTIONS_REGISTER; + break; + case PARTY_MENU_TYPE_UNION_ROOM_TRADE: + actionType = ACTIONS_TRADE; + break; + case PARTY_MENU_TYPE_SPIN_TRADE: + actionType = ACTIONS_SPIN_TRADE; + break; + // The following have no selection actions (i.e. they exit immediately upon selection) + // PARTY_MENU_TYPE_CONTEST + // PARTY_MENU_TYPE_CHOOSE_MON + // PARTY_MENU_TYPE_MULTI_SHOWCASE + // PARTY_MENU_TYPE_MOVE_RELEARNER + // PARTY_MENU_TYPE_MINIGAME + default: + actionType = ACTIONS_NONE; + break; + } + return actionType; +} + +void CreateSelectionWindow(void) +{ + struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId]; + + GetMonNickname(mon, gStringVar1); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]); + SetPartyMonSelectionActions(gPlayerParty, gPartyMenu.slotId, GetPartyMenuActionsType(mon)); + DisplaySelectionWindow(SELECTWINDOW_ACTIONS); + DisplayPartyMenuStdMessage(PARTY_MSG_DO_WHAT_WITH_MON); +} + +void Task_TryCreateSelectionWindow(u8 taskId) +{ + CreateSelectionWindow(); + gTasks[taskId].data[0] = 0xFF; + gTasks[taskId].func = Task_HandleSelectionMenuInput; +} + +void Task_HandleSelectionMenuInput(u8 taskId) +{ + if (!gPaletteFade.active && sub_80BF748() != TRUE) + { + s8 input; + s16 *data = gTasks[taskId].data; + + if (sPartyMenuInternal->numActions <= 3) + input = Menu_ProcessInputNoWrapAround_other(); + else + input = Menu_ProcessInput_other(); + if (data[0] != Menu_GetCursorPos()) + sub_8122138(sPartyMenuInternal->actions[Menu_GetCursorPos()]); + data[0] = Menu_GetCursorPos(); + switch (input) + { + case MENU_NOTHING_CHOSEN: + break; + case MENU_B_PRESSED: + PlaySE(SE_SELECT); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[2]); + sCursorOptions[sPartyMenuInternal->actions[sPartyMenuInternal->numActions - 1]].func(taskId); + break; + default: + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[2]); + sCursorOptions[sPartyMenuInternal->actions[input]].func(taskId); + break; + } + } +} + +void CursorCB_Summary(u8 taskId) +{ + PlaySE(SE_SELECT); + sPartyMenuInternal->exitCallback = CB2_ShowPokemonSummaryScreen; + Task_ClosePartyMenu(taskId); +} + +void CB2_ShowPokemonSummaryScreen(void) +{ + if (gPartyMenu.menuType == PARTY_MENU_TYPE_IN_BATTLE) + UpdatePartyToBattleOrder(); + ShowPokemonSummaryScreen(gPlayerParty, gPartyMenu.slotId, gPlayerPartyCount - 1, CB2_ReturnToPartyMenuFromSummaryScreen, 0); +} + +void CB2_ReturnToPartyMenuFromSummaryScreen(void) +{ + gPaletteFade.bufferTransferDisabled = TRUE; + gPartyMenu.slotId = GetLastViewedMonIndex(); + InitPartyMenu(gPartyMenu.menuType, KEEP_PARTY_LAYOUT, gPartyMenu.action, TRUE, PARTY_MSG_DO_WHAT_WITH_MON, Task_TryCreateSelectionWindow, gPartyMenu.exitCallback); +} + +void CursorCB_Switch(u8 taskId) +{ + PlaySE(SE_SELECT); + gPartyMenu.action = PARTY_ACTION_SWITCH; + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]); + DisplayPartyMenuStdMessage(PARTY_MSG_MOVE_TO_WHERE); + AnimatePartySlot(gPartyMenu.slotId, 1); + gPartyMenu.slotId2 = gPartyMenu.slotId; + gTasks[taskId].func = Task_HandleChooseMonInput; +} + +#define tSlot1Left data[0] +#define tSlot1Top data[1] +#define tSlot1Width data[2] +#define tSlot1Height data[3] +#define tSlot2Left data[4] +#define tSlot2Top data[5] +#define tSlot2Width data[6] +#define tSlot2Height data[7] +#define tSlot1Offset data[8] +#define tSlot2Offset data[9] +#define tSlot1SlideDir data[10] +#define tSlot2SlideDir data[11] + +void SwitchSelectedMons(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + u8 windowIds[2]; + + if (gPartyMenu.slotId2 == gPartyMenu.slotId) + { + FinishTwoMonAction(taskId); + } + else + { + // Initialize switching party mons slide animation + sub_812358C(); + windowIds[0] = sPartyMenuBoxes[gPartyMenu.slotId].windowId; + tSlot1Left = GetWindowAttribute(windowIds[0], WINDOW_TILEMAP_LEFT); + tSlot1Top = GetWindowAttribute(windowIds[0], WINDOW_TILEMAP_TOP); + tSlot1Width = GetWindowAttribute(windowIds[0], WINDOW_WIDTH); + tSlot1Height = GetWindowAttribute(windowIds[0], WINDOW_HEIGHT); + tSlot1Offset = 0; + if (tSlot1Width == 10) + tSlot1SlideDir = -1; + else + tSlot1SlideDir = 1; + windowIds[1] = sPartyMenuBoxes[gPartyMenu.slotId2].windowId; + tSlot2Left = GetWindowAttribute(windowIds[1], WINDOW_TILEMAP_LEFT); + tSlot2Top = GetWindowAttribute(windowIds[1], WINDOW_TILEMAP_TOP); + tSlot2Width = GetWindowAttribute(windowIds[1], WINDOW_WIDTH); + tSlot2Height = GetWindowAttribute(windowIds[1], WINDOW_HEIGHT); + tSlot2Offset = 0; + if (tSlot2Width == 10) + tSlot2SlideDir = -1; + else + tSlot2SlideDir = 1; + sSlot1TilemapBuffer = Alloc(tSlot1Width * (tSlot1Height << 1)); + sSlot2TilemapBuffer = Alloc(tSlot2Width * (tSlot2Height << 1)); + CopyToBufferFromBgTilemap(0, sSlot1TilemapBuffer, tSlot1Left, tSlot1Top, tSlot1Width, tSlot1Height); + CopyToBufferFromBgTilemap(0, sSlot2TilemapBuffer, tSlot2Left, tSlot2Top, tSlot2Width, tSlot2Height); + ClearWindowTilemap(windowIds[0]); + ClearWindowTilemap(windowIds[1]); + gPartyMenu.action = PARTY_ACTION_SWITCHING; + AnimatePartySlot(gPartyMenu.slotId, 1); + AnimatePartySlot(gPartyMenu.slotId2, 1); + SlidePartyMenuBoxOneStep(taskId); + gTasks[taskId].func = Task_SlideSelectedSlotsOffscreen; + } +} + +// returns FALSE if the slot has slid fully offscreen / back onscreen +bool8 TryMovePartySlot(s16 x, s16 width, u8 *leftMove, u8 *newX, u8 *newWidth) +{ + if ((x + width) < 0) + return FALSE; + if (x > 31) + return FALSE; + if (x < 0) + { + *leftMove = x * -1; + *newX = 0; + *newWidth = width + x; + } + else + { + *leftMove = 0; + *newX = x; + if ((x + width) > 31) + *newWidth = 32 - x; + else + *newWidth = width; + } + return TRUE; +} + +void MoveAndBufferPartySlot(const void *rectSrc, s16 x, s16 y, s16 width, s16 height, s16 dir) +{ + // The use of the dimension parameters here is a mess + u8 leftMove, newX, newWidth; // leftMove is used as a srcX, newX is used as both x and srcHeight, newWidth is used as both width and destY + + if (TryMovePartySlot(x, width, &leftMove, &newX, &newWidth)) + { + FillBgTilemapBufferRect_Palette0(0, 0, newX, y, newWidth, height); + if (TryMovePartySlot(x + dir, width, &leftMove, &newX, &newWidth)) + CopyRectToBgTilemapBufferRect(0, rectSrc, leftMove, 0, width, height, newX, y, newWidth, height, 17, 0, 0); + } +} + +void MovePartyMenuBoxSprites(struct PartyMenuBox *menuBox, s16 offset) +{ + gSprites[menuBox->pokeballSpriteId].pos2.x += offset * 8; + gSprites[menuBox->itemSpriteId].pos2.x += offset * 8; + gSprites[menuBox->monSpriteId].pos2.x += offset * 8; + gSprites[menuBox->statusSpriteId].pos2.x += offset * 8; +} + +void SlidePartyMenuBoxSpritesOneStep(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (tSlot1SlideDir != 0) + MovePartyMenuBoxSprites(&sPartyMenuBoxes[gPartyMenu.slotId], tSlot1SlideDir); + if (tSlot2SlideDir != 0) + MovePartyMenuBoxSprites(&sPartyMenuBoxes[gPartyMenu.slotId2], tSlot2SlideDir); +} + +void SlidePartyMenuBoxOneStep(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + if (tSlot1SlideDir != 0) + MoveAndBufferPartySlot(sSlot1TilemapBuffer, tSlot1Left + tSlot1Offset, tSlot1Top, tSlot1Width, tSlot1Height, tSlot1SlideDir); + if (tSlot2SlideDir != 0) + MoveAndBufferPartySlot(sSlot2TilemapBuffer, tSlot2Left + tSlot2Offset, tSlot2Top, tSlot2Width, tSlot2Height, tSlot2SlideDir); + ScheduleBgCopyTilemapToVram(0); +} + +void Task_SlideSelectedSlotsOffscreen(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + u16 slidingSlotPositions[2]; + + SlidePartyMenuBoxOneStep(taskId); + SlidePartyMenuBoxSpritesOneStep(taskId); + tSlot1Offset += tSlot1SlideDir; + tSlot2Offset += tSlot2SlideDir; + slidingSlotPositions[0] = tSlot1Left + tSlot1Offset; + slidingSlotPositions[1] = tSlot2Left + tSlot2Offset; + // Both slots have slid offscreen + if (slidingSlotPositions[0] > 33 && slidingSlotPositions[1] > 33) + { + tSlot1SlideDir *= -1; + tSlot2SlideDir *= -1; + SwitchPartyMon(); + DisplayPartyPokemonData(gPartyMenu.slotId); + DisplayPartyPokemonData(gPartyMenu.slotId2); + PutWindowTilemap(sPartyMenuBoxes[gPartyMenu.slotId].windowId); + PutWindowTilemap(sPartyMenuBoxes[gPartyMenu.slotId2].windowId); + CopyToBufferFromBgTilemap(0, sSlot1TilemapBuffer, tSlot1Left, tSlot1Top, tSlot1Width, tSlot1Height); + CopyToBufferFromBgTilemap(0, sSlot2TilemapBuffer, tSlot2Left, tSlot2Top, tSlot2Width, tSlot2Height); + ClearWindowTilemap(sPartyMenuBoxes[gPartyMenu.slotId].windowId); + ClearWindowTilemap(sPartyMenuBoxes[gPartyMenu.slotId2].windowId); + gTasks[taskId].func = Task_SlideSelectedSlotsOnscreen; + } +} + +void Task_SlideSelectedSlotsOnscreen(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + + SlidePartyMenuBoxOneStep(taskId); + SlidePartyMenuBoxSpritesOneStep(taskId); + + // Both slots have slide back onscreen + if (tSlot1SlideDir == 0 && tSlot2SlideDir == 0) + { + PutWindowTilemap(sPartyMenuBoxes[gPartyMenu.slotId].windowId); + PutWindowTilemap(sPartyMenuBoxes[gPartyMenu.slotId2].windowId); + ScheduleBgCopyTilemapToVram(0); + // memory leak + // Free(sSlot1TilemapBuffer); + // Free(sSlot2TilemapBuffer); + FinishTwoMonAction(taskId); + } + // Continue sliding + else + { + tSlot1Offset += tSlot1SlideDir; + tSlot2Offset += tSlot2SlideDir; + if (tSlot1Offset == 0) + tSlot1SlideDir = 0; + if (tSlot2Offset == 0) + tSlot2SlideDir = 0; + } +} + +void SwitchMenuBoxSprites(u8 *spriteIdPtr1, u8 *spriteIdPtr2) +{ + u8 spriteIdBuffer = *spriteIdPtr1; + u16 xBuffer1, yBuffer1, xBuffer2, yBuffer2; + + *spriteIdPtr1 = *spriteIdPtr2; + *spriteIdPtr2 = spriteIdBuffer; + xBuffer1 = gSprites[*spriteIdPtr1].pos1.x; + yBuffer1 = gSprites[*spriteIdPtr1].pos1.y; + xBuffer2 = gSprites[*spriteIdPtr1].pos2.x; + yBuffer2 = gSprites[*spriteIdPtr1].pos2.y; + gSprites[*spriteIdPtr1].pos1.x = gSprites[*spriteIdPtr2].pos1.x; + gSprites[*spriteIdPtr1].pos1.y = gSprites[*spriteIdPtr2].pos1.y; + gSprites[*spriteIdPtr1].pos2.x = gSprites[*spriteIdPtr2].pos2.x; + gSprites[*spriteIdPtr1].pos2.y = gSprites[*spriteIdPtr2].pos2.y; + gSprites[*spriteIdPtr2].pos1.x = xBuffer1; + gSprites[*spriteIdPtr2].pos1.y = yBuffer1; + gSprites[*spriteIdPtr2].pos2.x = xBuffer2; + gSprites[*spriteIdPtr2].pos2.y = yBuffer2; +} + +void SwitchPartyMon(void) +{ + struct PartyMenuBox *menuBoxes[2]; + struct Pokemon *mon1, *mon2; + struct Pokemon *monBuffer; + + menuBoxes[0] = &sPartyMenuBoxes[gPartyMenu.slotId]; + menuBoxes[1] = &sPartyMenuBoxes[gPartyMenu.slotId2]; + mon1 = &gPlayerParty[gPartyMenu.slotId]; + mon2 = &gPlayerParty[gPartyMenu.slotId2]; + monBuffer = Alloc(sizeof(struct Pokemon)); + *monBuffer = *mon1; + *mon1 = *mon2; + *mon2 = *monBuffer; + Free(monBuffer); + SwitchMenuBoxSprites(&menuBoxes[0]->pokeballSpriteId, &menuBoxes[1]->pokeballSpriteId); + SwitchMenuBoxSprites(&menuBoxes[0]->itemSpriteId, &menuBoxes[1]->itemSpriteId); + SwitchMenuBoxSprites(&menuBoxes[0]->monSpriteId, &menuBoxes[1]->monSpriteId); + SwitchMenuBoxSprites(&menuBoxes[0]->statusSpriteId, &menuBoxes[1]->statusSpriteId); +} + +void sub_812358C(void) +{ + u16 *buffer = Alloc(2 * sizeof(u16)); + + buffer[0] = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_SPECIES2); + buffer[1] = GetMonData(&gPlayerParty[gPartyMenu.slotId2], MON_DATA_SPECIES2); + sub_8113550(3, buffer); + Free(buffer); +} + +// Finish switching mons or using Softboiled +void FinishTwoMonAction(u8 taskId) +{ + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]); + gPartyMenu.action = PARTY_ACTION_CHOOSE_MON; + AnimatePartySlot(gPartyMenu.slotId, 0); + gPartyMenu.slotId = gPartyMenu.slotId2; + AnimatePartySlot(gPartyMenu.slotId2, 1); + DisplayPartyMenuStdMessage(PARTY_MSG_CHOOSE_MON); + gTasks[taskId].func = Task_HandleChooseMonInput; +} + +#undef tSlot1Left +#undef tSlot1Top +#undef tSlot1Width +#undef tSlot1Height +#undef tSlot2Left +#undef tSlot2Top +#undef tSlot2Width +#undef tSlot2Height +#undef tSlot1Offset +#undef tSlot2Offset +#undef tSlot1SlideDir +#undef tSlot2SlideDir + +void CursorCB_Cancel1(u8 taskId) +{ + PlaySE(SE_SELECT); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]); + if (gPartyMenu.menuType == PARTY_MENU_TYPE_DAYCARE) + DisplayPartyMenuStdMessage(PARTY_MSG_CHOOSE_MON_2); + else + DisplayPartyMenuStdMessage(PARTY_MSG_CHOOSE_MON); + gTasks[taskId].func = Task_HandleChooseMonInput; +} + +void CursorCB_Item(u8 taskId) +{ + PlaySE(SE_SELECT); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]); + SetPartyMonSelectionActions(gPlayerParty, gPartyMenu.slotId, ACTIONS_ITEM); + DisplaySelectionWindow(SELECTWINDOW_ITEM); + DisplayPartyMenuStdMessage(PARTY_MSG_DO_WHAT_WITH_ITEM); + gTasks[taskId].data[0] = 0xFF; + gTasks[taskId].func = Task_HandleSelectionMenuInput; +} + +void CursorCB_Give(u8 taskId) +{ + PlaySE(SE_SELECT); + sPartyMenuInternal->exitCallback = CB2_SelectBagItemToGive; + Task_ClosePartyMenu(taskId); +} + +void CB2_SelectBagItemToGive(void) +{ + GoToBagMenu(1, 3, CB2_GiveHoldItem); +} + +void CB2_GiveHoldItem(void) +{ + if (gSpecialVar_ItemId == ITEM_NONE) + { + InitPartyMenu(gPartyMenu.menuType, KEEP_PARTY_LAYOUT, gPartyMenu.action, TRUE, PARTY_MSG_NONE, Task_TryCreateSelectionWindow, gPartyMenu.exitCallback); + } + else + { + sPartyMenuItemId = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_HELD_ITEM); + // Already holding item + if (sPartyMenuItemId != ITEM_NONE) + { + InitPartyMenu(gPartyMenu.menuType, KEEP_PARTY_LAYOUT, gPartyMenu.action, TRUE, PARTY_MSG_NONE, Task_SwitchHoldItemsPrompt, gPartyMenu.exitCallback); + } + // Give mail + else if (ItemIsMail(gSpecialVar_ItemId)) + { + RemoveBagItem(gSpecialVar_ItemId, 1); + GiveItemToMon(&gPlayerParty[gPartyMenu.slotId], gSpecialVar_ItemId); + CB2_WriteMailToGiveMon(); + } + // Give item + else + { + InitPartyMenu(gPartyMenu.menuType, KEEP_PARTY_LAYOUT, gPartyMenu.action, TRUE, PARTY_MSG_NONE, Task_GiveHoldItem, gPartyMenu.exitCallback); + } + } +} + +void Task_GiveHoldItem(u8 taskId) +{ + u16 item; + + if (!gPaletteFade.active) + { + item = gSpecialVar_ItemId; + DisplayGaveHeldItemMessage(&gPlayerParty[gPartyMenu.slotId], item, FALSE, 0); + GiveItemToMon(&gPlayerParty[gPartyMenu.slotId], item); + RemoveBagItem(item, 1); + gTasks[taskId].func = Task_UpdateHeldItemSprite; } } diff --git a/src/pokemon_icon.c b/src/pokemon_icon.c index f3492593c..4c7681231 100644 --- a/src/pokemon_icon.c +++ b/src/pokemon_icon.c @@ -1276,7 +1276,7 @@ static void DestroyMonIconInternal(struct Sprite * sprite) DestroySprite(sprite); } -void MonIcon_SetAnim(struct Sprite * sprite, u8 animNum) +void SetPartyHPBarSprite(struct Sprite * sprite, u8 animNum) { sprite->animNum = animNum; sprite->animDelayCounter = 0; diff --git a/src/quest_log.c b/src/quest_log.c index 9683d7799..04369f1c2 100644 --- a/src/quest_log.c +++ b/src/quest_log.c @@ -1972,15 +1972,15 @@ void DestroyHelpMessageWindow(u8 a0) } #ifdef NONMATCHING -void sub_8112F18(u8 a0) +void sub_8112F18(u8 windowId) { - u8 width = GetWindowAttribute(a0, WINDOW_WIDTH); - u8 height = GetWindowAttribute(a0, WINDOW_HEIGHT); + u8 width = GetWindowAttribute(windowId, WINDOW_WIDTH); + u8 height = GetWindowAttribute(windowId, WINDOW_HEIGHT); u8 *buffer = Alloc(32 * width * height); u8 i, j; u8 k; - if (buffer) + if (buffer != NULL) { for (i = 0; i < height; i++) { @@ -1999,13 +1999,13 @@ void sub_8112F18(u8 a0) ); } } - CopyToWindowPixelBuffer(a0, buffer, width * height * 32, 0); + CopyToWindowPixelBuffer(windowId, buffer, width * height * 32, 0); Free(buffer); } } #else NAKED -void sub_8112F18(u8 a0) +void sub_8112F18(u8 windowId) { asm_unified("\tpush {r4-r7,lr}\n" "\tmov r7, r10\n" diff --git a/src/trade.c b/src/trade.c index 85bd7b2ca..537a5503b 100644 --- a/src/trade.c +++ b/src/trade.c @@ -2053,9 +2053,9 @@ void sub_804CF14(void) } if (sTradeMenuResourcesPtr->tradeMenuCursorPosition < 6) - sTradeMenuResourcesPtr->tradeMenuCursorPosition = sub_8138B20(); + sTradeMenuResourcesPtr->tradeMenuCursorPosition = GetLastViewedMonIndex(); else - sTradeMenuResourcesPtr->tradeMenuCursorPosition = sub_8138B20() + 6; + sTradeMenuResourcesPtr->tradeMenuCursorPosition = GetLastViewedMonIndex() + 6; sTradeMenuResourcesPtr->tradeMenuCursorSpriteIdx = CreateSprite(&sSpriteTemplate_TradeButtons, sTradeMonSpriteCoords[sTradeMenuResourcesPtr->tradeMenuCursorPosition][0] * 8 + 32, sTradeMonSpriteCoords[sTradeMenuResourcesPtr->tradeMenuCursorPosition][1] * 8, 2); gMain.state = 16; @@ -2633,14 +2633,14 @@ void sub_804CF14(void) "\tldrb r0, [r0]\n" "\tcmp r0, 0x5\n" "\tbhi _0804D3B8\n" - "\tbl sub_8138B20\n" + "\tbl GetLastViewedMonIndex\n" "\tldr r1, [r4]\n" "\tb _0804D3C0\n" "\t.align 2, 0\n" "_0804D3B0: .4byte sSpriteTemplate_Text\n" "_0804D3B4: .4byte sTradeMenuResourcesPtr\n" "_0804D3B8:\n" - "\tbl sub_8138B20\n" + "\tbl GetLastViewedMonIndex\n" "\tldr r1, [r4]\n" "\tadds r0, 0x6\n" "_0804D3C0:\n" @@ -4243,7 +4243,7 @@ static void sub_804F964(void) { for (j = 0; j < sTradeMenuResourcesPtr->partyCounts[i]; j++) { - MonIcon_SetAnim(&gSprites[sTradeMenuResourcesPtr->partyIcons[i][j]], 4 - sTradeMenuResourcesPtr->unk_5D[i][j]); + SetPartyHPBarSprite(&gSprites[sTradeMenuResourcesPtr->partyIcons[i][j]], 4 - sTradeMenuResourcesPtr->unk_5D[i][j]); } } } |