#include "global.h" #include "bg.h" #include "event_data.h" #include "field_screen.h" #include "field_weather.h" #include "gpu_regs.h" #include "international_string_util.h" #include "main.h" #include "menu.h" #include "overworld.h" #include "palette.h" #include "pokemon.h" #include "pokemon_storage_system.h" #include "script.h" #include "sound.h" #include "string_util.h" #include "strings.h" #include "text.h" #include "walda_phrase.h" #include "window.h" #include "constants/songs.h" #include "constants/species.h" IWRAM_DATA u8 gUnknown_03000F78[0x188]; extern const u8 gText_PartyFull[]; extern const u8 gText_Box[]; extern const u8 gText_JustOnePkmn[]; extern u8 gUnknown_02039D00; // This file's functions. void StorageSystemCreatePrimaryMenu(u8 whichMenu, s16 *windowIdPtr); void sub_80C7D74(u8); u8 sub_80CAEA0(void); void SetBoxWallpaper(u8 boxId, u8 wallpaperId); void SetCurrentBox(u8 boxId); void ClearMonInBox(u8 boxId, u8 boxPos); void ResetWaldaWallpaper(void); void sub_80C7958(u8 curBox); void sub_80C7B14(void); void sub_80C7BB4(void); void sub_80CA028(void); void sub_80C7B80(void); void sub_80D2AA4(void); void sub_80C7BE4(void); void sub_80CAA14(void); void sub_80C7CF4(struct Sprite *sprite); struct Sprite *sub_80CD2E8(u16 x, u16 y, u8 animId, u8 priority, u8 subpriority); // const rom data const struct PSS_MenuStringPtrs gUnknown_085716C0[] = { {gText_WithdrawPokemon, gText_WithdrawMonDescription}, {gText_DepositPokemon, gText_DepositMonDescription}, {gText_MovePokemon, gText_MoveMonDescription}, {gText_MoveItems, gText_MoveItemsDescription}, {gText_SeeYa, gText_SeeYaDescription} }; const struct WindowTemplate gUnknown_085716E8 = {0, 1, 1, 0x11, 0xA, 0xF, 1}; static const union AnimCmd sSpriteAnim_85716F0[] = { ANIMCMD_FRAME(0, 5), ANIMCMD_END }; static const union AnimCmd sSpriteAnim_85716F8[] = { ANIMCMD_FRAME(4, 5), ANIMCMD_END }; static const union AnimCmd sSpriteAnim_8571700[] = { ANIMCMD_FRAME(6, 5), ANIMCMD_END }; static const union AnimCmd sSpriteAnim_8571708[] = { ANIMCMD_FRAME(10, 5), ANIMCMD_END }; const union AnimCmd *const sSpriteAnimTable_8571710[] = { sSpriteAnim_85716F0, sSpriteAnim_85716F8, sSpriteAnim_8571700, sSpriteAnim_8571708 }; static const union AffineAnimCmd sSpriteAffineAnim_8571720[] = { AFFINEANIMCMD_FRAME(0xE0, 0xE0, 0, 0), AFFINEANIMCMD_END }; static const union AffineAnimCmd *const sSpriteAffineAnimTable_8571730[] = { sSpriteAffineAnim_8571720 }; const u8 gUnknown_08571734[] = {4, 0xF, 0xE}; const u8 gUnknown_08571737[] = _("/30"); const u16 gBoxSelectionPopupPalette[] = INCBIN_U16("graphics/unknown/unknown_57173C.gbapal"); const u8 gBoxSelectionPopupCenterTiles[] = INCBIN_U8("graphics/pokemon_storage/box_selection_popup_center.4bpp"); const u8 gBoxSelectionPopupSidesTiles[] = INCBIN_U8("graphics/pokemon_storage/box_selection_popup_sides.4bpp"); // code u8 CountMonsInBox(u8 boxId) { u16 i, count; for (i = 0, count = 0; i < IN_BOX_COUNT; i++) { if (GetBoxMonDataFromAnyBox(boxId, i, MON_DATA_SPECIES) != SPECIES_NONE) count++; } return count; } s16 GetFirstFreeBoxSpot(u8 boxId) { u16 i; for (i = 0; i < IN_BOX_COUNT; i++) { if (GetBoxMonDataFromAnyBox(boxId, i, MON_DATA_SPECIES) == SPECIES_NONE) return i; } return -1; // all spots are taken } u8 CountPartyNonEggMons(void) { u16 i, count; for (i = 0, count = 0; i < PARTY_SIZE; i++) { if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) != SPECIES_NONE && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) { count++; } } return count; } u8 CountPartyAliveNonEggMonsExcept(u8 slotToIgnore) { u16 i, count; for (i = 0, count = 0; i < PARTY_SIZE; i++) { if (i != slotToIgnore && GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) != SPECIES_NONE && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) && GetMonData(&gPlayerParty[i], MON_DATA_HP) != 0) { count++; } } return count; } u16 CountPartyAliveNonEggMons_IgnoreVar0x8004Slot(void) { return CountPartyAliveNonEggMonsExcept(gSpecialVar_0x8004); } u8 CountPartyMons(void) { u16 i, count; for (i = 0, count = 0; i < PARTY_SIZE; i++) { if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) != SPECIES_NONE) { count++; } } return count; } static u8 *StringCopyAndFillWithSpaces(u8 *dst, const u8 *src, u16 n) { u8 *str; for (str = StringCopy(dst, src); str < dst + n; str++) *str = CHAR_SPACE; *str = EOS; return str; } static void sub_80C7128(u16 *dest, u16 dest_left, u16 dest_top, const u16 *src, u16 src_left, u16 src_top, u16 dest_width, u16 dest_height, u16 src_width) { u16 i; dest_width *= 2; dest += dest_top * 0x20 + dest_left; src += src_top * src_width + src_left; for (i = 0; i < dest_height; i++) { CpuCopy16(src, dest, dest_width); dest += 0x20; src += src_width; } } #define MAX_DMA_BLOCK_SIZE 0x1000 #define Dma3FillLarge_(value, dest, size, bit) \ { \ void *_dest = dest; \ u32 _size = size; \ while (1) \ { \ if (_size <= MAX_DMA_BLOCK_SIZE) \ { \ DmaFill##bit(3, value, _dest, _size); \ break; \ } \ DmaFill##bit(3, value, _dest, MAX_DMA_BLOCK_SIZE); \ _dest += MAX_DMA_BLOCK_SIZE; \ _size -= MAX_DMA_BLOCK_SIZE; \ } \ } #define Dma3FillLarge16_(value, dest, size) Dma3FillLarge_(value, dest, size, 16) #define Dma3FillLarge32_(value, dest, size) Dma3FillLarge_(value, dest, size, 32) void sub_80C71A4(u16 *dest, u16 dest_left, u16 dest_top, u16 width, u16 height) { u16 i; dest += dest_top * 0x20 + dest_left; width *= 2; for (i = 0; i < height; dest += 0x20, i++) Dma3FillLarge16_(0, dest, width); } void Task_PokemonStorageSystem(u8 taskId) { struct Task *task = gTasks + taskId; switch (task->data[0]) { case 0: StorageSystemCreatePrimaryMenu(task->data[1], &task->data[15]); sub_81973A4(); NewMenuHelpers_DrawDialogueFrame(0, 0); FillWindowPixelBuffer(0, 0x11); AddTextPrinterParameterized2(0, 1, gUnknown_085716C0[task->data[1]].desc, TEXT_SPEED_FF, NULL, 2, 1, 3); CopyWindowToVram(0, 3); CopyWindowToVram(task->data[15], 3); task->data[0]++; break; case 1: if (IsWeatherNotFadingIn()) { task->data[0]++; } break; case 2: task->data[2] = Menu_ProcessInput(); switch(task->data[2]) { case -2: task->data[3] = task->data[1]; if (gMain.newKeys & DPAD_UP && --task->data[3] < 0) task->data[3] = 4; if (gMain.newKeys & DPAD_DOWN && ++task->data[3] > 4) task->data[3] = 0; if (task->data[1] != task->data[3]) { task->data[1] = task->data[3]; FillWindowPixelBuffer(0, 0x11); AddTextPrinterParameterized2(0, 1, gUnknown_085716C0[task->data[1]].desc, 0, NULL, 2, 1, 3); } break; case -1: case 4: sub_819746C(task->data[15], TRUE); ScriptContext2_Disable(); EnableBothScriptContexts(); RemoveWindow(task->data[15]); DestroyTask(taskId); break; default: if (task->data[2] == 0 && CountPartyMons() == PARTY_SIZE) { FillWindowPixelBuffer(0, 0x11); AddTextPrinterParameterized2(0, 1, gText_PartyFull, 0, NULL, 2, 1, 3); task->data[0] = 3; } else if (task->data[2] == 1 && CountPartyMons() == 1) { FillWindowPixelBuffer(0, 0x11); AddTextPrinterParameterized2(0, 1, gText_JustOnePkmn, 0, NULL, 2, 1, 3); task->data[0] = 3; } else { FadeScreen(1, 0); task->data[0] = 4; } break; } break; case 3: if (gMain.newKeys & (A_BUTTON | B_BUTTON)) { FillWindowPixelBuffer(0, 0x11); AddTextPrinterParameterized2(0, 1, gUnknown_085716C0[task->data[1]].desc, 0, NULL, 2, 1, 3); task->data[0] = 2; } else if (gMain.newKeys & DPAD_UP) { if (--task->data[1] < 0) task->data[1] = 4; MoveMenuCursor(-1); task->data[1] = GetMenuCursorPos(); FillWindowPixelBuffer(0, 0x11); AddTextPrinterParameterized2(0, 1, gUnknown_085716C0[task->data[1]].desc, 0, NULL, 2, 1, 3); task->data[0] = 2; } else if (gMain.newKeys & DPAD_DOWN) { if (++task->data[1] > 3) task->data[1] = 0; MoveMenuCursor(1); task->data[1] = GetMenuCursorPos(); FillWindowPixelBuffer(0, 0x11); AddTextPrinterParameterized2(0, 1, gUnknown_085716C0[task->data[1]].desc, 0, NULL, 2, 1, 3); task->data[0] = 2; } break; case 4: if (!gPaletteFade.active) { overworld_free_bg_tilemaps(); sub_80C7D74(task->data[2]); RemoveWindow(task->data[15]); DestroyTask(taskId); } break; } } void ShowPokemonStorageSystem(void) { u8 taskId = CreateTask(Task_PokemonStorageSystem, 80); gTasks[taskId].data[0] = 0; gTasks[taskId].data[1] = 0; ScriptContext2_Enable(); } void mapldr_0808C6D8(void) { u8 taskId; MainCallback vblankCb = gMain.vblankCallback; SetVBlankCallback(NULL); taskId = CreateTask(Task_PokemonStorageSystem, 80); gTasks[taskId].data[0] = 0; gTasks[taskId].data[1] = gUnknown_02039D00; Task_PokemonStorageSystem(taskId); SetVBlankCallback(vblankCb); pal_fill_black(); } void StorageSystemCreatePrimaryMenu(u8 whichMenu, s16 *windowIdPtr) { s16 windowId; struct WindowTemplate winTemplate = gUnknown_085716E8; winTemplate.width = GetMaxWidthInMenuTable((void *)gUnknown_085716C0, ARRAY_COUNT(gUnknown_085716C0)); windowId = AddWindow(&winTemplate); NewMenuHelpers_DrawStdWindowFrame(windowId, FALSE); PrintMenuTable(windowId, ARRAY_COUNT(gUnknown_085716C0), (void *)gUnknown_085716C0); InitMenuInUpperLeftCornerPlaySoundWhenAPressed(windowId, ARRAY_COUNT(gUnknown_085716C0), whichMenu); *windowIdPtr = windowId; } void sub_80C7678(void) { gUnknown_02039D00 = sub_80CAEA0(); gFieldCallback = mapldr_0808C6D8; SetMainCallback2(CB2_ReturnToField); } s16 StorageSystemGetNextMonIndex(struct BoxPokemon *box, s8 startIdx, u8 stopIdx, u8 mode) { s16 i; s16 direction; if (mode == 0 || mode == 1) { direction = 1; } else { direction = -1; } if (mode == 1 || mode == 3) { for (i = startIdx + direction; i >= 0 && i <= stopIdx; i += direction) { if (GetBoxMonData(box + i, MON_DATA_SPECIES) != 0) return i; } } else { for (i = startIdx + direction; i >= 0 && i <= stopIdx; i += direction) { if (GetBoxMonData(box + i, MON_DATA_SPECIES) != 0 && !GetBoxMonData(box + i, MON_DATA_IS_EGG)) return i; } } return -1; } void ResetPokemonStorageSystem(void) { u16 boxId; u16 boxMon; SetCurrentBox(0); for (boxId = 0; boxId < TOTAL_BOXES_COUNT; boxId++) { for (boxMon = 0; boxMon < IN_BOX_COUNT; boxMon++) ClearMonInBox(boxId, boxMon); } for (boxId = 0; boxId < TOTAL_BOXES_COUNT; boxId++) { u8 *dest = StringCopy(GetBoxNamePtr(boxId), gText_Box); ConvertIntToDecimalStringN(dest, boxId + 1, STR_CONV_MODE_LEFT_ALIGN, 2); } for (boxId = 0; boxId < TOTAL_BOXES_COUNT; boxId++) { SetBoxWallpaper(boxId, boxId % 4); } ResetWaldaWallpaper(); } void sub_80C77E8(struct UnkPSSStruct_2002370 *a0, u16 tileTag, u16 palTag, u8 a3, bool32 loadPal) { struct SpritePalette palette = { gBoxSelectionPopupPalette, palTag }; struct SpriteSheet sheets[] = { {gBoxSelectionPopupCenterTiles, 0x800, tileTag}, {gBoxSelectionPopupSidesTiles, 0x180, tileTag + 1}, {} }; if (loadPal) LoadSpritePalette(&palette); LoadSpriteSheets(sheets); gUnknown_02039D04 = a0; a0->unk_0240 = tileTag; a0->unk_0242 = palTag; a0->unk_0246 = a3; a0->unk_023c = loadPal; } void sub_80C7890(void) { if (gUnknown_02039D04->unk_023c) FreeSpritePaletteByTag(gUnknown_02039D04->unk_0242); FreeSpriteTilesByTag(gUnknown_02039D04->unk_0240); FreeSpriteTilesByTag(gUnknown_02039D04->unk_0240 + 1); } void sub_80C78D4(u8 curBox) { sub_80C7958(curBox); } void sub_80C78E4(void) { sub_80C7B14(); } u8 sub_80C78F0(void) { if (gMain.newKeys & B_BUTTON) { PlaySE(SE_SELECT); return 201; } if (gMain.newKeys & A_BUTTON) { PlaySE(SE_SELECT); return gUnknown_02039D04->curBox; } if (gMain.newKeys & DPAD_LEFT) { PlaySE(SE_SELECT); sub_80C7BB4(); } else if (gMain.newKeys & DPAD_RIGHT) { PlaySE(SE_SELECT); sub_80C7B80(); } return 200; } void sub_80C7958(u8 curBox) { u16 i; u8 spriteId; struct SpriteTemplate template; struct OamData oamData = {}; oamData.size = 3; oamData.paletteNum = 1; template = (struct SpriteTemplate){ 0, 0, &oamData, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy }; gUnknown_02039D04->curBox = curBox; template.tileTag = gUnknown_02039D04->unk_0240; template.paletteTag = gUnknown_02039D04->unk_0242; spriteId = CreateSprite(&template, 0xA0, 0x60, 0); gUnknown_02039D04->unk_0000 = gSprites + spriteId; oamData.shape = ST_OAM_V_RECTANGLE; oamData.size = 1; template.tileTag = gUnknown_02039D04->unk_0240 + 1; template.anims = sSpriteAnimTable_8571710; for (i = 0; i < 4; i++) { u16 r5; spriteId = CreateSprite(&template, 0x7c, 0x50, gUnknown_02039D04->unk_0246); gUnknown_02039D04->unk_0004[i] = gSprites + spriteId; r5 = 0; if (i & 2) { gUnknown_02039D04->unk_0004[i]->pos1.x = 0xc4; r5 = 2; } if (i & 1) { gUnknown_02039D04->unk_0004[i]->pos1.y = 0x70; gUnknown_02039D04->unk_0004[i]->oam.size = 0; r5++; } StartSpriteAnim(gUnknown_02039D04->unk_0004[i], r5); } for (i = 0; i < 2; i++) { gUnknown_02039D04->unk_0020[i] = sub_80CD2E8(72 * i + 0x7c, 0x58, i, 0, gUnknown_02039D04->unk_0246); if (gUnknown_02039D04->unk_0020[i]) { gUnknown_02039D04->unk_0020[i]->data[0] = (i == 0 ? -1 : 1); gUnknown_02039D04->unk_0020[i]->callback = sub_80C7CF4; } } sub_80C7BE4(); } void sub_80C7B14(void) { u16 i; if (gUnknown_02039D04->unk_0000) { DestroySprite(gUnknown_02039D04->unk_0000); gUnknown_02039D04->unk_0000 = NULL; } for (i = 0; i < 4; i++) { if (gUnknown_02039D04->unk_0004[i]) { DestroySprite(gUnknown_02039D04->unk_0004[i]); gUnknown_02039D04->unk_0004[i] = NULL; } } for (i = 0; i < 2; i++) { if (gUnknown_02039D04->unk_0020[i]) DestroySprite(gUnknown_02039D04->unk_0020[i]); } } void sub_80C7B80(void) { if (++gUnknown_02039D04->curBox >= TOTAL_BOXES_COUNT) gUnknown_02039D04->curBox = 0; sub_80C7BE4(); } void sub_80C7BB4(void) { gUnknown_02039D04->curBox = (gUnknown_02039D04->curBox == 0 ? TOTAL_BOXES_COUNT - 1 : gUnknown_02039D04->curBox - 1); sub_80C7BE4(); } void sub_80C7BE4(void) { u8 text[16]; struct WindowTemplate winTemplate; u8 windowId; u8 *boxName = GetBoxNamePtr(gUnknown_02039D04->curBox); u8 nPokemonInBox = CountMonsInBox(gUnknown_02039D04->curBox); u32 winTileData; s32 center; memset(&winTemplate, 0, sizeof(winTemplate)); winTemplate.width = 8; winTemplate.height = 4; windowId = AddWindow(&winTemplate); FillWindowPixelBuffer(windowId, 0x44); center = GetStringCenterAlignXOffset(1, boxName, 0x40); AddTextPrinterParameterized3(windowId, 1, center, 1, gUnknown_08571734, TEXT_SPEED_FF, boxName); ConvertIntToDecimalStringN(text, nPokemonInBox, 1, 2); StringAppend(text, gUnknown_08571737); center = GetStringCenterAlignXOffset(1, text, 0x40); AddTextPrinterParameterized3(windowId, 1, center, 0x11, gUnknown_08571734, TEXT_SPEED_FF, text); winTileData = GetWindowAttribute(windowId, WINDOW_TILE_DATA); CpuCopy32((void *)winTileData, (void *)OBJ_VRAM0 + 0x100 + (GetSpriteTileStartByTag(gUnknown_02039D04->unk_0240) * 32), 0x400); RemoveWindow(windowId); } void sub_80C7CF4(struct Sprite *sprite) { if (++sprite->data[1] > 3) { sprite->data[1] = 0; sprite->pos2.x += sprite->data[0]; if (++sprite->data[2] > 5) { sprite->data[2] = 0; sprite->pos2.x = 0; } } } void sub_80C7D28(void) { LoadOam(); ProcessSpriteCopyRequests(); sub_80D2AA4(); TransferPlttBuffer(); SetGpuReg(REG_OFFSET_BG2HOFS, gUnknown_02039D08->bg2_X); } void c2_Box(void) { RunTasks(); do_scheduled_bg_tilemap_copies_to_vram(); sub_80CA028(); sub_80CAA14(); AnimateSprites(); BuildOamBuffer(); }