#include "global.h" #include "battle.h" #include "battle_factory_screen.h" #include "battle_factory.h" #include "sprite.h" #include "event_data.h" #include "overworld.h" #include "random.h" #include "battle_tower.h" #include "text.h" #include "palette.h" #include "task.h" #include "main.h" #include "malloc.h" #include "bg.h" #include "gpu_regs.h" #include "string_util.h" #include "international_string_util.h" #include "window.h" #include "data.h" #include "decompress.h" #include "pokemon_summary_screen.h" #include "sound.h" #include "pokedex.h" #include "util.h" #include "trainer_pokemon_sprites.h" #include "starter_choose.h" #include "strings.h" #include "graphics.h" #include "constants/battle_frontier.h" #include "constants/songs.h" #include "constants/rgb.h" // Select_ refers to the first Pokemon selection screen where you choose your initial 3 rental Pokemon. // Swap_ refers to the subsequent selection screens where you can swap a Pokemon with one from the beaten trainer // Note that, generally, "Action" will refer to the immediate actions that can be taken on each screen, // i.e. selecting a pokemon or selecting the Cancel button // The "Options menu" will refer to the popup menu that shows when some actions have been selected #define SWAP_PLAYER_SCREEN 0 // The screen where the player selects which of their pokemon to swap away #define SWAP_ENEMY_SCREEN 1 // The screen where the player selects which new pokemon from the defeated party to swap for #define SELECTABLE_MONS_COUNT 6 enum { PALTAG_BALL_GRAY = 100, PALTAG_BALL_SELECTED, PALTAG_INTERFACE, PALTAG_MON_PIC_BG, }; enum { GFXTAG_BALL = 100, GFXTAG_ARROW, GFXTAG_MENU_HIGHLIGHT_LEFT, GFXTAG_MENU_HIGHLIGHT_RIGHT, GFXTAG_ACTION_BOX_LEFT, GFXTAG_ACTION_BOX_RIGHT, GFXTAG_ACTION_HIGHLIGHT_LEFT, GFXTAG_ACTION_HIGHLIGHT_MIDDLE, GFXTAG_ACTION_HIGHLIGHT_RIGHT, GFXTAG_MON_PIC_BG_ANIM, }; // Tasks in this file universally use data[0] as a state for switches #define tState data[0] // States for both Select/Swap versions of Task_FadeSpeciesName enum { FADESTATE_INIT, FADESTATE_RUN, FADESTATE_DELAY }; // Return states for the Select Actions enum { SELECT_SUMMARY, SELECT_CONTINUE_CHOOSING, SELECT_CONFIRM_MONS, SELECT_INVALID_MON, }; struct FactorySelectableMon { u16 monId; u16 ballSpriteId; u8 selectedId; // 0 - not selected, 1 - first pokemon, 2 - second pokemon, 3 - third pokemon struct Pokemon monData; }; struct FactoryMonPic { u8 monSpriteId; u8 bgSpriteId; }; struct FactorySelectScreen { u8 menuCursorPos; u8 menuCursor1SpriteId; u8 menuCursor2SpriteId; u8 cursorPos; u8 cursorSpriteId; u8 selectingMonsState; bool8 fromSummaryScreen; u8 yesNoCursorPos; u8 unused; struct FactorySelectableMon mons[SELECTABLE_MONS_COUNT]; struct FactoryMonPic monPics[FRONTIER_PARTY_SIZE]; // Array so all chosen mons can be shown at once bool8 monPicAnimating; u8 fadeSpeciesNameTaskId; bool8 fadeSpeciesNameActive; u16 speciesNameColorBackup; bool8 fadeSpeciesNameFadeOut; u8 fadeSpeciesNameCoeffDelay; u8 fadeSpeciesNameCoeff; u8 faceSpeciesNameDelay; }; struct SwapScreenAction { u8 id; void (*func)(u8 taskId); }; struct FactorySwapScreen { u8 menuCursorPos; u8 menuCursor1SpriteId; u8 menuCursor2SpriteId; u8 cursorPos; u8 cursorSpriteId; u8 ballSpriteIds[FRONTIER_PARTY_SIZE]; u8 pkmnForSwapButtonSpriteIds[2][3]; // For this and sprite ID array below, [0][i] is the button background, [1][i] is the button highlight u8 cancelButtonSpriteIds[2][2]; u8 playerMonId; u8 enemyMonId; bool8 inEnemyScreen; bool8 fromSummaryScreen; u8 yesNoCursorPos; u8 actionsCount; const struct SwapScreenAction *actionsData; u8 unused[4]; bool8 monSwapped; u8 fadeSpeciesNameTaskId; bool8 fadeSpeciesNameActive; u16 speciesNameColorBackup; bool8 fadeSpeciesNameFadeOut; u8 fadeSpeciesNameCoeffDelay; u8 fadeSpeciesNameCoeff; u8 faceSpeciesNameDelay; struct FactoryMonPic monPic; bool8 monPicAnimating; }; static void SpriteCB_Pokeball(struct Sprite *); static void SpriteCB_OpenMonPic(struct Sprite *); static void OpenMonPic(u8 *, bool8 *, bool8); static void HideMonPic(struct FactoryMonPic, bool8 *); static void CloseMonPic(struct FactoryMonPic, bool8 *, bool8); static void Task_OpenMonPic(u8); static void Task_CloseMonPic(u8); // Select screen static void CB2_InitSelectScreen(void); static void Select_SetWinRegs(s16, s16, s16, s16); static void Select_InitMonsData(void); static void Select_InitAllSprites(void); static void Select_ReshowMonSprite(void); static void Select_PrintSelectMonString(void); static void Select_PrintMonSpecies(void); static void Select_PrintMonCategory(void); static void Select_PrintRentalPkmnString(void); static void Select_CopyMonsToPlayerParty(void); static void Select_ShowChosenMons(void); static void Select_ShowYesNoOptions(void); static void Select_HideChosenMons(void); static void Select_ShowMenuOptions(void); static void Select_PrintMenuOptions(void); static void Select_PrintYesNoOptions(void); static void Select_Task_FadeSpeciesName(u8); static void Select_Task_OpenChosenMonPics(u8); static void Select_Task_HandleChooseMons(u8); static void Select_Task_HandleMenu(u8); static void CreateFrontierFactorySelectableMons(u8); static void CreateSlateportTentSelectableMons(u8); static void Select_SetBallSpritePaletteNum(u8); static void Select_ErasePopupMenu(u8); static u8 Select_RunMenuOptionFunc(void); static u8 Select_DeclineChosenMons(void); static u8 Select_OptionSummary(void); static u8 Select_OptionOthers(void); static u8 Select_OptionRentDeselect(void); static bool32 Select_AreSpeciesValid(u16); // Swap screen static void CB2_InitSwapScreen(void); static void Swap_DestroyAllSprites(void); static void Swap_ShowYesNoOptions(void); static void Swap_HideActionButtonHighlights(void); static void Swap_EraseSpeciesWindow(void); static void Swap_UpdateYesNoCursorPosition(s8); static void Swap_UpdateMenuCursorPosition(s8); static void Swap_ErasePopupMenu(u8); static void Swap_Task_ScreenInfoTransitionIn(u8); static void Swap_Task_HandleChooseMons(u8); static void Swap_Task_ScreenInfoTransitionOut(u8); static void Swap_PrintOnInfoWindow(const u8 *); static void Swap_ShowMenuOptions(void); static void Swap_PrintMenuOptions(void); static void Swap_PrintYesNoOptions(void); static void Swap_PrintMonSpecies(void); static void Swap_PrintMonSpeciesAtFade(void); static void Swap_PrintMonSpeciesForTransition(void); static void Swap_PrintMonCategory(void); static void Swap_InitAllSprites(void); static void Swap_PrintPkmnSwap(void); static void Swap_EraseSpeciesAtFadeWindow(void); static void Swap_EraseActionFadeWindow(void); static void Swap_ShowSummaryMonSprite(void); static void Swap_UpdateActionCursorPosition(s8); static void Swap_UpdateBallCursorPosition(s8); static void Swap_RunMenuOptionFunc(u8); static void Swap_OptionSwap(u8); static void Swap_OptionSummary(u8); static void Swap_OptionRechoose(u8); static void Swap_RunActionFunc(u8); static void Swap_TaskCantHaveSameMons(u8); static void Swap_CreateMonSprite(void); static void Swap_PrintActionStrings(void); static void Swap_PrintActionStrings2(void); static void Swap_PrintOneActionString(u8); static void Swap_InitActions(u8); static void Swap_HighlightActionButton(u8); static bool8 Swap_AlreadyHasSameSpecies(u8); static void Swap_ActionMon(u8); static void Swap_ActionCancel(u8); static void Swap_ActionPkmnForSwap(u8); static EWRAM_DATA u8 *sSelectMenuTilesetBuffer = NULL; static EWRAM_DATA u8 *sSelectMonPicBgTilesetBuffer = NULL; static EWRAM_DATA u8 *sSelectMenuTilemapBuffer = NULL; static EWRAM_DATA u8 *sSelectMonPicBgTilemapBuffer = NULL; static EWRAM_DATA struct Pokemon *sFactorySelectMons = NULL; static EWRAM_DATA u8 *sSwapMenuTilesetBuffer = NULL; static EWRAM_DATA u8 *sSwapMonPicBgTilesetBuffer = NULL; static EWRAM_DATA u8 *sSwapMenuTilemapBuffer = NULL; static EWRAM_DATA u8 *sSwapMonPicBgTilemapBuffer = NULL; static struct FactorySelectScreen *sFactorySelectScreen; static void (*sSwap_CurrentOptionFunc)(u8 taskId); static struct FactorySwapScreen *sFactorySwapScreen; u8 (*gFactorySelect_CurrentOptionFunc)(void); static const u16 sPokeballGray_Pal[] = INCBIN_U16("graphics/battle_frontier/factory_screen/pokeball_gray.gbapal"); static const u16 sPokeballSelected_Pal[] = INCBIN_U16("graphics/battle_frontier/factory_screen/pokeball_selected.gbapal"); static const u16 sInterface_Pal[] = INCBIN_U16("graphics/battle_frontier/factory_screen/interface.gbapal"); // Arrow, menu/action highlights, action box, etc static const u8 sPokeball_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/pokeball.4bpp"); // Unused, gPokeballSelection_Gfx used instead static const u8 sArrow_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/arrow.4bpp"); static const u8 sMenuHighlightLeft_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/menu_highlight_left.4bpp"); static const u8 sMenuHighlightRight_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/menu_highlight_right.4bpp"); static const u8 sActionBoxLeft_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/action_box_left.4bpp"); static const u8 sActionBoxRight_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/action_box_right.4bpp"); static const u8 sActionHighlightLeft_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/action_highlight_left.4bpp"); static const u8 sActionHighlightMiddle_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/action_highlight_middle.4bpp"); static const u8 sActionHighlightRight_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/action_highlight_right.4bpp"); static const u8 sMonPicBgAnim_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/mon_pic_bg_anim.4bpp"); static const u8 sMonPicBg_Tilemap[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/mon_pic_bg.bin"); static const u8 sMonPicBg_Gfx[] = INCBIN_U8( "graphics/battle_frontier/factory_screen/mon_pic_bg.4bpp"); static const u16 sMonPicBg_Pal[] = INCBIN_U16("graphics/battle_frontier/factory_screen/mon_pic_bg.gbapal"); static const struct SpriteSheet sSelect_SpriteSheets[] = { {sArrow_Gfx, sizeof(sArrow_Gfx), GFXTAG_ARROW}, {sMenuHighlightLeft_Gfx, sizeof(sMenuHighlightLeft_Gfx), GFXTAG_MENU_HIGHLIGHT_LEFT}, {sMenuHighlightRight_Gfx, sizeof(sMenuHighlightRight_Gfx), GFXTAG_MENU_HIGHLIGHT_RIGHT}, {sMonPicBgAnim_Gfx, sizeof(sMonPicBgAnim_Gfx), GFXTAG_MON_PIC_BG_ANIM}, {}, }; static const struct CompressedSpriteSheet sSelect_BallGfx[] = { {gPokeballSelection_Gfx, 0x800, GFXTAG_BALL}, {}, }; static const struct SpritePalette sSelect_SpritePalettes[] = { {sPokeballGray_Pal, PALTAG_BALL_GRAY}, {sPokeballSelected_Pal, PALTAG_BALL_SELECTED}, {sInterface_Pal, PALTAG_INTERFACE}, {sMonPicBg_Pal, PALTAG_MON_PIC_BG}, {}, }; u8 static (* const sSelect_MenuOptionFuncs[])(void) = { Select_OptionSummary, Select_OptionRentDeselect, Select_OptionOthers }; static const struct BgTemplate sSelect_BgTemplates[] = { { .bg = 0, .charBaseIndex = 0, .mapBaseIndex = 24, .screenSize = 0, .paletteMode = 0, .priority = 0, .baseTile = 0 }, { .bg = 1, .charBaseIndex = 1, .mapBaseIndex = 25, .screenSize = 0, .paletteMode = 0, .priority = 3, .baseTile = 0 }, { .bg = 3, .charBaseIndex = 2, .mapBaseIndex = 27, .screenSize = 0, .paletteMode = 0, .priority = 2, .baseTile = 0 }, }; enum { SELECT_WIN_TITLE, SELECT_WIN_SPECIES, SELECT_WIN_INFO, SELECT_WIN_OPTIONS, SELECT_WIN_YES_NO, SELECT_WIN_MON_CATEGORY, }; static const struct WindowTemplate sSelect_WindowTemplates[] = { [SELECT_WIN_TITLE] = { .bg = 0, .tilemapLeft = 0, .tilemapTop = 2, .width = 12, .height = 2, .paletteNum = 15, .baseBlock = 0x0001, }, [SELECT_WIN_SPECIES] = { .bg = 0, .tilemapLeft = 19, .tilemapTop = 2, .width = 11, .height = 2, .paletteNum = 14, .baseBlock = 0x0019, }, [SELECT_WIN_INFO] = { .bg = 0, .tilemapLeft = 0, .tilemapTop = 15, .width = 20, .height = 3, .paletteNum = 15, .baseBlock = 0x002f, }, [SELECT_WIN_OPTIONS] = { .bg = 0, .tilemapLeft = 22, .tilemapTop = 14, .width = 8, .height = 6, .paletteNum = 15, .baseBlock = 0x006b, }, [SELECT_WIN_YES_NO] = { .bg = 0, .tilemapLeft = 22, .tilemapTop = 14, .width = 8, .height = 4, .paletteNum = 15, .baseBlock = 0x009b, }, [SELECT_WIN_MON_CATEGORY] = { .bg = 0, .tilemapLeft = 15, .tilemapTop = 0, .width = 15, .height = 2, .paletteNum = 15, .baseBlock = 0x00bb, }, DUMMY_WIN_TEMPLATE, }; static const u16 sSelectText_Pal[] = INCBIN_U16("graphics/battle_frontier/factory_screen/text.gbapal"); static const u8 sMenuOptionTextColors[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GREY, TEXT_COLOR_TRANSPARENT}; static const u8 sSpeciesNameTextColors[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_RED, TEXT_COLOR_TRANSPARENT}; static const struct OamData sOam_Select_Pokeball = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x32), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(32x32), .tileNum = 0, .priority = 3, .paletteNum = 0, .affineParam = 0, }; static const struct OamData sOam_Select_Arrow = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(16x16), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(16x16), .tileNum = 0, .priority = 3, .paletteNum = 0, .affineParam = 0, }; static const struct OamData sOam_Select_MenuHighlight = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x16), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(32x16), .tileNum = 0, .priority = 2, .paletteNum = 0, .affineParam = 0, }; static const struct OamData sOam_Select_MonPicBgAnim = { .y = 0, .affineMode = ST_OAM_AFFINE_DOUBLE, .objMode = ST_OAM_OBJ_BLEND, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(64x64), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(64x64), .tileNum = 0, .priority = 0, .paletteNum = 0, .affineParam = 1, }; static const union AnimCmd sAnim_Select_Interface[] = { ANIMCMD_FRAME(0, 1), ANIMCMD_END, }; static const union AnimCmd sAnim_Select_MonPicBgAnim[] = { ANIMCMD_FRAME(0, 1), ANIMCMD_END, }; static const union AnimCmd sAnim_Select_Pokeball_Still[] = { ANIMCMD_FRAME(0, 30), ANIMCMD_END, }; static const union AnimCmd sAnim_Select_Pokeball_Moving[] = { ANIMCMD_FRAME(16, 4), ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(32, 4), ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(16, 4), ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(32, 4), ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(0, 32), ANIMCMD_FRAME(16, 8), ANIMCMD_FRAME(0, 8), ANIMCMD_FRAME(32, 8), ANIMCMD_FRAME(0, 8), ANIMCMD_FRAME(16, 8), ANIMCMD_FRAME(0, 8), ANIMCMD_FRAME(32, 8), ANIMCMD_FRAME(0, 8), ANIMCMD_END, }; static const union AnimCmd * const sAnims_Select_Interface[] = { sAnim_Select_Interface, }; static const union AnimCmd * const sAnims_Select_MonPicBgAnim[] = { sAnim_Select_MonPicBgAnim, }; static const union AnimCmd * const sAnims_Select_Pokeball[] = { sAnim_Select_Pokeball_Still, sAnim_Select_Pokeball_Moving, }; static const union AffineAnimCmd sAffineAnim_Select_MonPicBg_Opening[] = { AFFINEANIMCMD_FRAME(5, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(16, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(32, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(64, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(128, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(256, 5, 0, 0), AFFINEANIMCMD_END, }; static const union AffineAnimCmd sAffineAnim_Select_MonPicBg_Closing[] = { AFFINEANIMCMD_FRAME(128, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(64, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(32, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(16, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(5, 5, 0, 0), AFFINEANIMCMD_END, }; static const union AffineAnimCmd sAffineAnim_Select_MonPicBg_Open[] = { AFFINEANIMCMD_FRAME(256, 256, 0, 0), AFFINEANIMCMD_END, }; static const union AffineAnimCmd * const sAffineAnims_Select_MonPicBgAnim[] = { sAffineAnim_Select_MonPicBg_Opening, sAffineAnim_Select_MonPicBg_Closing, sAffineAnim_Select_MonPicBg_Open, }; static const struct SpriteTemplate sSpriteTemplate_Select_Pokeball = { .tileTag = GFXTAG_BALL, .paletteTag = PALTAG_BALL_GRAY, .oam = &sOam_Select_Pokeball, .anims = sAnims_Select_Pokeball, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_Pokeball }; static const struct SpriteTemplate sSpriteTemplate_Select_Arrow = { .tileTag = GFXTAG_ARROW, .paletteTag = PALTAG_INTERFACE, .oam = &sOam_Select_Arrow, .anims = sAnims_Select_Interface, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_Select_MenuHighlightLeft = { .tileTag = GFXTAG_MENU_HIGHLIGHT_LEFT, .paletteTag = PALTAG_INTERFACE, .oam = &sOam_Select_MenuHighlight, .anims = sAnims_Select_Interface, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_Select_MenuHighlightRight = { .tileTag = GFXTAG_MENU_HIGHLIGHT_RIGHT, .paletteTag = PALTAG_INTERFACE, .oam = &sOam_Select_MenuHighlight, .anims = sAnims_Select_Interface, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_Select_MonPicBgAnim = { .tileTag = GFXTAG_MON_PIC_BG_ANIM, .paletteTag = PALTAG_MON_PIC_BG, .oam = &sOam_Select_MonPicBgAnim, .anims = sAnims_Select_MonPicBgAnim, .images = NULL, .affineAnims = sAffineAnims_Select_MonPicBgAnim, .callback = SpriteCallbackDummy }; static const struct SpriteSheet sSwap_SpriteSheets[] = { {sArrow_Gfx, sizeof(sArrow_Gfx), GFXTAG_ARROW}, {sMenuHighlightLeft_Gfx, sizeof(sMenuHighlightLeft_Gfx), GFXTAG_MENU_HIGHLIGHT_LEFT}, {sMenuHighlightRight_Gfx, sizeof(sMenuHighlightRight_Gfx), GFXTAG_MENU_HIGHLIGHT_RIGHT}, {sActionBoxLeft_Gfx, sizeof(sActionBoxLeft_Gfx), GFXTAG_ACTION_BOX_LEFT}, {sActionBoxRight_Gfx, sizeof(sActionBoxRight_Gfx), GFXTAG_ACTION_BOX_RIGHT}, {sActionHighlightLeft_Gfx, 0x100, GFXTAG_ACTION_HIGHLIGHT_LEFT}, {sActionHighlightMiddle_Gfx, sizeof(sActionHighlightMiddle_Gfx), GFXTAG_ACTION_HIGHLIGHT_MIDDLE}, {sActionHighlightRight_Gfx, sizeof(sActionHighlightRight_Gfx), GFXTAG_ACTION_HIGHLIGHT_RIGHT}, {sMonPicBgAnim_Gfx, sizeof(sMonPicBgAnim_Gfx), GFXTAG_MON_PIC_BG_ANIM}, {}, }; static const struct CompressedSpriteSheet sSwap_BallGfx[] = { {gPokeballSelection_Gfx, 0x800, GFXTAG_BALL}, {}, }; static const struct SpritePalette sSwap_SpritePalettes[] = { {sPokeballGray_Pal, PALTAG_BALL_GRAY}, {sPokeballSelected_Pal, PALTAG_BALL_SELECTED}, {sInterface_Pal, PALTAG_INTERFACE}, {sMonPicBg_Pal, PALTAG_MON_PIC_BG}, {}, }; static const struct OamData sOam_Swap_Pokeball = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x32), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(32x32), .tileNum = 0, .priority = 3, .paletteNum = 0, .affineParam = 0, }; static const struct OamData sOam_Swap_Arrow = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(16x16), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(16x16), .tileNum = 0, .priority = 3, .paletteNum = 0, .affineParam = 0, }; static const struct OamData sOam_Swap_MenuHighlight = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x16), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(32x16), .tileNum = 0, .priority = 2, .paletteNum = 0, .affineParam = 0, }; static const struct OamData sOam_Swap_MonPicBgAnim = { .y = 0, .affineMode = ST_OAM_AFFINE_DOUBLE, .objMode = ST_OAM_OBJ_BLEND, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(64x64), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(64x64), .tileNum = 0, .priority = 0, .paletteNum = 0, .affineParam = 1, }; static const union AnimCmd sAnim_Swap_Interface[] = { ANIMCMD_FRAME(0, 1), ANIMCMD_END, }; static const union AnimCmd sAnim_Swap_MonPicBgAnim[] = { ANIMCMD_FRAME(0, 1), ANIMCMD_END, }; static const union AnimCmd sAnim_Swap_Pokeball_Still[] = { ANIMCMD_FRAME(0, 30), ANIMCMD_END, }; static const union AnimCmd sAnim_Swap_Pokeball_Moving[] = { ANIMCMD_FRAME(16, 4), ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(32, 4), ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(16, 4), ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(32, 4), ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(0, 32), ANIMCMD_FRAME(16, 8), ANIMCMD_FRAME(0, 8), ANIMCMD_FRAME(32, 8), ANIMCMD_FRAME(0, 8), ANIMCMD_FRAME(16, 8), ANIMCMD_FRAME(0, 8), ANIMCMD_FRAME(32, 8), ANIMCMD_FRAME(0, 8), ANIMCMD_END, }; static const union AnimCmd * const sAnims_Swap_Interface[] = { sAnim_Swap_Interface, }; static const union AnimCmd * const sAnims_Swap_MonPicBgAnim[] = { sAnim_Swap_MonPicBgAnim, }; static const union AnimCmd * const sAnims_Swap_Pokeball[] = { sAnim_Swap_Pokeball_Still, sAnim_Swap_Pokeball_Moving, }; static const union AffineAnimCmd sAffineAnim_Swap_MonPicBg_Opening[] = { AFFINEANIMCMD_FRAME(5, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(16, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(32, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(64, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(128, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(256, 5, 0, 0), AFFINEANIMCMD_END, }; static const union AffineAnimCmd sAffineAnim_Swap_MonPicBg_Closing[] = { AFFINEANIMCMD_FRAME(128, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(64, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(32, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(16, 5, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_FRAME(5, 5, 0, 0), AFFINEANIMCMD_END, }; static const union AffineAnimCmd sAffineAnim_Swap_MonPicBg_Open[] = { AFFINEANIMCMD_FRAME(256, 256, 0, 0), AFFINEANIMCMD_END, }; static const union AffineAnimCmd * const sAffineAnims_Swap_MonPicBgAnim[] = { sAffineAnim_Swap_MonPicBg_Opening, sAffineAnim_Swap_MonPicBg_Closing, sAffineAnim_Swap_MonPicBg_Open, }; static const struct SpriteTemplate sSpriteTemplate_Swap_Pokeball = { .tileTag = GFXTAG_BALL, .paletteTag = PALTAG_BALL_GRAY, .oam = &sOam_Swap_Pokeball, .anims = sAnims_Swap_Pokeball, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_Pokeball }; static const struct SpriteTemplate sSpriteTemplate_Swap_Arrow = { .tileTag = GFXTAG_ARROW, .paletteTag = PALTAG_INTERFACE, .oam = &sOam_Swap_Arrow, .anims = sAnims_Swap_Interface, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_Swap_MenuHighlightLeft = { .tileTag = GFXTAG_MENU_HIGHLIGHT_LEFT, .paletteTag = PALTAG_INTERFACE, .oam = &sOam_Swap_MenuHighlight, .anims = sAnims_Swap_Interface, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_Swap_MenuHighlightRight = { .tileTag = GFXTAG_MENU_HIGHLIGHT_RIGHT, .paletteTag = PALTAG_INTERFACE, .oam = &sOam_Swap_MenuHighlight, .anims = sAnims_Swap_Interface, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_Swap_MonPicBgAnim = { .tileTag = GFXTAG_MON_PIC_BG_ANIM, .paletteTag = PALTAG_MON_PIC_BG, .oam = &sOam_Swap_MonPicBgAnim, .anims = sAnims_Swap_MonPicBgAnim, .images = NULL, .affineAnims = sAffineAnims_Swap_MonPicBgAnim, .callback = SpriteCallbackDummy }; void static (* const sSwap_MenuOptionFuncs[])(u8 taskId) = { Swap_OptionSummary, Swap_OptionSwap, Swap_OptionRechoose, }; static const struct BgTemplate sSwap_BgTemplates[4] = { { .bg = 0, .charBaseIndex = 0, .mapBaseIndex = 24, .screenSize = 0, .paletteMode = 0, .priority = 1, .baseTile = 0 }, { .bg = 1, .charBaseIndex = 1, .mapBaseIndex = 25, .screenSize = 0, .paletteMode = 0, .priority = 3, .baseTile = 0 }, { .bg = 2, .charBaseIndex = 2, .mapBaseIndex = 26, .screenSize = 0, .paletteMode = 0, .priority = 0, .baseTile = 0 }, { .bg = 3, .charBaseIndex = 2, .mapBaseIndex = 27, .screenSize = 0, .paletteMode = 0, .priority = 2, .baseTile = 0 }, }; enum { SWAP_WIN_TITLE, SWAP_WIN_SPECIES, SWAP_WIN_INFO, SWAP_WIN_OPTIONS, SWAP_WIN_YES_NO, SWAP_WIN_ACTION_FADE, // Used for action text fading out during screen transition SWAP_WIN_UNUSED, SWAP_WIN_SPECIES_AT_FADE, // Used to print species name stopped at current fade level SWAP_WIN_MON_CATEGORY, }; static const struct WindowTemplate sSwap_WindowTemplates[] = { [SWAP_WIN_TITLE] = { .bg = 0, .tilemapLeft = 0, .tilemapTop = 2, .width = 12, .height = 2, .paletteNum = 15, .baseBlock = 0x0001, }, [SWAP_WIN_SPECIES] = { .bg = 2, .tilemapLeft = 19, .tilemapTop = 2, .width = 11, .height = 2, .paletteNum = 14, .baseBlock = 0x0019, }, [SWAP_WIN_INFO] = { .bg = 0, .tilemapLeft = 0, .tilemapTop = 15, .width = 20, .height = 3, .paletteNum = 15, .baseBlock = 0x002f, }, [SWAP_WIN_OPTIONS] = { .bg = 0, .tilemapLeft = 21, .tilemapTop = 14, .width = 9, .height = 6, .paletteNum = 15, .baseBlock = 0x006b, }, [SWAP_WIN_YES_NO] = { .bg = 0, .tilemapLeft = 22, .tilemapTop = 14, .width = 8, .height = 4, .paletteNum = 15, .baseBlock = 0x00a1, }, [SWAP_WIN_ACTION_FADE] = { .bg = 2, .tilemapLeft = 21, .tilemapTop = 15, .width = 9, .height = 5, .paletteNum = 14, .baseBlock = 0x006b, }, [SWAP_WIN_UNUSED] = { .bg = 2, .tilemapLeft = 10, .tilemapTop = 2, .width = 4, .height = 2, .paletteNum = 14, .baseBlock = 0x00c1, }, [SWAP_WIN_SPECIES_AT_FADE] = { .bg = 0, .tilemapLeft = 19, .tilemapTop = 2, .width = 11, .height = 2, .paletteNum = 15, .baseBlock = 0x00c9, }, [SWAP_WIN_MON_CATEGORY] = { .bg = 0, .tilemapLeft = 15, .tilemapTop = 0, .width = 15, .height = 2, .paletteNum = 15, .baseBlock = 0x00df, }, DUMMY_WIN_TEMPLATE, }; static const u16 sSwapText_Pal[] = INCBIN_U16("graphics/battle_frontier/factory_screen/text.gbapal"); // Identical to sSelectText_Pal static const u8 sSwapMenuOptionsTextColors[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GREY, TEXT_COLOR_TRANSPARENT}; static const u8 sSwapSpeciesNameTextColors[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_RED, TEXT_COLOR_TRANSPARENT}; #define SWAPACTION_MON 1 #define SWAPACTION_PKMN_FOR_SWAP 2 #define SWAPACTION_CANCEL 3 static const struct SwapScreenAction sSwap_PlayerScreenActions[] = { {.id = SWAPACTION_MON, .func = Swap_ActionMon}, {.id = SWAPACTION_MON, .func = Swap_ActionMon}, {.id = SWAPACTION_MON, .func = Swap_ActionMon}, {.id = SWAPACTION_CANCEL, .func = Swap_ActionCancel}, }; static const struct SwapScreenAction sSwap_EnemyScreenActions[] = { {.id = SWAPACTION_MON, .func = Swap_ActionMon}, {.id = SWAPACTION_MON, .func = Swap_ActionMon}, {.id = SWAPACTION_MON, .func = Swap_ActionMon}, {.id = SWAPACTION_PKMN_FOR_SWAP, .func = Swap_ActionPkmnForSwap}, {.id = SWAPACTION_CANCEL, .func = Swap_ActionCancel}, }; static void SpriteCB_Pokeball(struct Sprite *sprite) { if (sprite->oam.paletteNum == IndexOfSpritePaletteTag(PALTAG_BALL_SELECTED)) { // Pokeball selected, do rocking animation if (sprite->animEnded) { if (sprite->data[0] != 0) { sprite->data[0]--; } else if (Random() % 5 == 0) { StartSpriteAnim(sprite, 0); sprite->data[0] = 32; } else { StartSpriteAnim(sprite, 1); } } else { StartSpriteAnimIfDifferent(sprite, 1); } } else { // Pokeball not selected, remain still StartSpriteAnimIfDifferent(sprite, 0); } } static void CB2_SelectScreen(void) { AnimateSprites(); BuildOamBuffer(); RunTextPrinters(); UpdatePaletteFade(); RunTasks(); } static void VBlankCB_SelectScreen(void) { LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); } void DoBattleFactorySelectScreen(void) { sFactorySelectScreen = NULL; SetMainCallback2(CB2_InitSelectScreen); } // Main select states // States for the main tasks of the Select_ functions after initialization, including: // Select_Task_OpenSummaryScreen, Select_Task_HandleYesNo, Select_Task_HandleMenu, and Select_Task_HandleChooseMons // Unnecessarily complicated, could easily have just kept states numbered in each task always starting at 0 // There's only one instance (Select_Task_HandleChooseMons) where a non-initial case is used // Select_Task_Exit has its own straightforward states #define STATE_CHOOSE_MONS_INIT 0 #define STATE_CHOOSE_MONS_HANDLE_INPUT 1 #define STATE_MENU_INIT 2 #define STATE_MENU_HANDLE_INPUT 3 #define STATE_YESNO_SHOW_OPTIONS 4 #define STATE_YESNO_HANDLE_INPUT 5 #define STATE_SUMMARY_FADE 6 #define STATE_SUMMARY_CLEAN 7 #define STATE_SUMMARY_SHOW 8 #define STATE_MENU_SHOW_OPTIONS 9 #define STATE_YESNO_SHOW_MONS 10 #define STATE_CHOOSE_MONS_INVALID 11 #define STATE_MENU_REINIT 12 #define STATE_MENU_RESHOW 13 static void CB2_InitSelectScreen(void) { u8 taskId; switch (gMain.state) { case 0: if (sFactorySelectMons != NULL) FREE_AND_SET_NULL(sFactorySelectMons); SetHBlankCallback(NULL); SetVBlankCallback(NULL); CpuFill32(0, (void *)VRAM, VRAM_SIZE); ResetBgsAndClearDma3BusyFlags(0); InitBgsFromTemplates(0, sSelect_BgTemplates, ARRAY_COUNT(sSelect_BgTemplates)); InitWindows(sSelect_WindowTemplates); DeactivateAllTextPrinters(); gMain.state++; break; case 1: sSelectMenuTilesetBuffer = Alloc(0x440); sSelectMonPicBgTilesetBuffer = AllocZeroed(0x440); sSelectMenuTilemapBuffer = Alloc(BG_SCREEN_SIZE); sSelectMonPicBgTilemapBuffer = AllocZeroed(BG_SCREEN_SIZE); ChangeBgX(0, 0, 0); ChangeBgY(0, 0, 0); ChangeBgX(1, 0, 0); ChangeBgY(1, 0, 0); ChangeBgX(3, 0, 0); ChangeBgY(3, 0, 0); SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); SetGpuReg(REG_OFFSET_BLDY, 0); SetGpuReg(REG_OFFSET_MOSAIC, 0); SetGpuReg(REG_OFFSET_WIN0H, 0); SetGpuReg(REG_OFFSET_WIN0V, 0); SetGpuReg(REG_OFFSET_WIN1H, 0); SetGpuReg(REG_OFFSET_WIN1V, 0); SetGpuReg(REG_OFFSET_WININ, 0); SetGpuReg(REG_OFFSET_WINOUT, 0); gMain.state++; break; case 2: ResetPaletteFade(); ResetSpriteData(); ResetTasks(); FreeAllSpritePalettes(); CpuCopy16(gFrontierFactorySelectMenu_Gfx, sSelectMenuTilesetBuffer, 0x440); CpuCopy16(sMonPicBg_Gfx, sSelectMonPicBgTilesetBuffer, 0x60); LoadBgTiles(1, sSelectMenuTilesetBuffer, 0x440, 0); LoadBgTiles(3, sSelectMonPicBgTilesetBuffer, 0x60, 0); CpuCopy16(gFrontierFactorySelectMenu_Tilemap, sSelectMenuTilemapBuffer, BG_SCREEN_SIZE); LoadBgTilemap(1, sSelectMenuTilemapBuffer, BG_SCREEN_SIZE, 0); LoadPalette(gFrontierFactorySelectMenu_Pal, 0, 0x40); LoadPalette(sSelectText_Pal, 0xF0, 8); LoadPalette(sSelectText_Pal, 0xE0, 10); #ifdef UBFIX if (sFactorySelectScreen && sFactorySelectScreen->fromSummaryScreen) #else if (sFactorySelectScreen->fromSummaryScreen == TRUE) #endif gPlttBufferUnfaded[228] = sFactorySelectScreen->speciesNameColorBackup; LoadPalette(sMonPicBg_Pal, 0x20, 4); gMain.state++; break; case 3: SetBgTilemapBuffer(3, sSelectMonPicBgTilemapBuffer); CopyToBgTilemapBufferRect(3, sMonPicBg_Tilemap, 11, 4, 8, 8); CopyToBgTilemapBufferRect(3, sMonPicBg_Tilemap, 2, 4, 8, 8); CopyToBgTilemapBufferRect(3, sMonPicBg_Tilemap, 20, 4, 8, 8); CopyBgTilemapBufferToVram(3); gMain.state++; break; case 4: LoadSpritePalettes(sSelect_SpritePalettes); LoadSpriteSheets(sSelect_SpriteSheets); LoadCompressedSpriteSheet(sSelect_BallGfx); ShowBg(0); ShowBg(1); SetVBlankCallback(VBlankCB_SelectScreen); BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_BG0_ON | DISPCNT_BG1_ON | DISPCNT_OBJ_1D_MAP); #ifdef UBFIX if (sFactorySelectScreen && sFactorySelectScreen->fromSummaryScreen) #else if (sFactorySelectScreen->fromSummaryScreen == TRUE) #endif { Select_SetWinRegs(88, 152, 32, 96); ShowBg(3); SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG3 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_OBJ); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(11, 4)); } else { HideBg(3); } gMain.state++; break; case 5: #ifdef UBFIX if (sFactorySelectScreen && sFactorySelectScreen->fromSummaryScreen) #else if (sFactorySelectScreen->fromSummaryScreen == TRUE) #endif sFactorySelectScreen->cursorPos = gLastViewedMonIndex; Select_InitMonsData(); Select_InitAllSprites(); if (sFactorySelectScreen->fromSummaryScreen == TRUE) Select_ReshowMonSprite(); gMain.state++; break; case 6: Select_PrintSelectMonString(); PutWindowTilemap(SELECT_WIN_INFO); gMain.state++; break; case 7: Select_PrintMonCategory(); PutWindowTilemap(SELECT_WIN_MON_CATEGORY); gMain.state++; break; case 8: Select_PrintMonSpecies(); PutWindowTilemap(SELECT_WIN_SPECIES); gMain.state++; break; case 9: Select_PrintRentalPkmnString(); PutWindowTilemap(SELECT_WIN_TITLE); gMain.state++; break; case 10: sFactorySelectScreen->fadeSpeciesNameTaskId = CreateTask(Select_Task_FadeSpeciesName, 0); if (!sFactorySelectScreen->fromSummaryScreen) { gTasks[sFactorySelectScreen->fadeSpeciesNameTaskId].tState = FADESTATE_INIT; taskId = CreateTask(Select_Task_HandleChooseMons, 0); gTasks[taskId].tState = STATE_CHOOSE_MONS_INIT; } else { gTasks[sFactorySelectScreen->fadeSpeciesNameTaskId].tState = FADESTATE_RUN; sFactorySelectScreen->fadeSpeciesNameActive = FALSE; taskId = CreateTask(Select_Task_HandleMenu, 0); gTasks[taskId].tState = STATE_MENU_RESHOW; } SetMainCallback2(CB2_SelectScreen); break; } } static void Select_InitMonsData(void) { u8 i; if (sFactorySelectScreen != NULL) return; sFactorySelectScreen = AllocZeroed(sizeof(*sFactorySelectScreen)); sFactorySelectScreen->cursorPos = 0; sFactorySelectScreen->selectingMonsState = 1; sFactorySelectScreen->fromSummaryScreen = FALSE; for (i = 0; i < SELECTABLE_MONS_COUNT; i++) sFactorySelectScreen->mons[i].selectedId = 0; if (gSaveBlock2Ptr->frontier.lvlMode != FRONTIER_LVL_TENT) CreateFrontierFactorySelectableMons(0); else CreateSlateportTentSelectableMons(0); } static void Select_InitAllSprites(void) { u8 i, cursorPos; s16 x; for (i = 0; i < SELECTABLE_MONS_COUNT; i++) { sFactorySelectScreen->mons[i].ballSpriteId = CreateSprite(&sSpriteTemplate_Select_Pokeball, (35 * i) + 32, 64, 1); gSprites[sFactorySelectScreen->mons[i].ballSpriteId].data[0] = 0; Select_SetBallSpritePaletteNum(i); } cursorPos = sFactorySelectScreen->cursorPos; x = gSprites[sFactorySelectScreen->mons[cursorPos].ballSpriteId].pos1.x; sFactorySelectScreen->cursorSpriteId = CreateSprite(&sSpriteTemplate_Select_Arrow, x, 88, 0); sFactorySelectScreen->menuCursor1SpriteId = CreateSprite(&sSpriteTemplate_Select_MenuHighlightLeft, 176, 112, 0); sFactorySelectScreen->menuCursor2SpriteId = CreateSprite(&sSpriteTemplate_Select_MenuHighlightRight, 176, 144, 0); gSprites[sFactorySelectScreen->menuCursor1SpriteId].invisible = TRUE; gSprites[sFactorySelectScreen->menuCursor2SpriteId].invisible = TRUE; gSprites[sFactorySelectScreen->menuCursor1SpriteId].centerToCornerVecX = 0; gSprites[sFactorySelectScreen->menuCursor1SpriteId].centerToCornerVecY = 0; gSprites[sFactorySelectScreen->menuCursor2SpriteId].centerToCornerVecX = 0; gSprites[sFactorySelectScreen->menuCursor2SpriteId].centerToCornerVecY = 0; } static void Select_DestroyAllSprites(void) { u8 i; for (i = 0; i < SELECTABLE_MONS_COUNT; i++) DestroySprite(&gSprites[sFactorySelectScreen->mons[i].ballSpriteId]); DestroySprite(&gSprites[sFactorySelectScreen->cursorSpriteId]); DestroySprite(&gSprites[sFactorySelectScreen->menuCursor1SpriteId]); DestroySprite(&gSprites[sFactorySelectScreen->menuCursor2SpriteId]); } static void Select_UpdateBallCursorPosition(s8 direction) { u8 cursorPos; if (direction > 0) // Move cursor right. { if (sFactorySelectScreen->cursorPos != SELECTABLE_MONS_COUNT - 1) sFactorySelectScreen->cursorPos++; else sFactorySelectScreen->cursorPos = 0; } else // Move cursor left. { if (sFactorySelectScreen->cursorPos != 0) sFactorySelectScreen->cursorPos--; else sFactorySelectScreen->cursorPos = SELECTABLE_MONS_COUNT - 1; } cursorPos = sFactorySelectScreen->cursorPos; gSprites[sFactorySelectScreen->cursorSpriteId].pos1.x = gSprites[sFactorySelectScreen->mons[cursorPos].ballSpriteId].pos1.x; } static void Select_UpdateMenuCursorPosition(s8 direction) { if (direction > 0) // Move cursor down. { if (sFactorySelectScreen->menuCursorPos != ARRAY_COUNT(sSelect_MenuOptionFuncs) - 1) sFactorySelectScreen->menuCursorPos++; else sFactorySelectScreen->menuCursorPos = 0; } else // Move cursor up. { if (sFactorySelectScreen->menuCursorPos != 0) sFactorySelectScreen->menuCursorPos--; else sFactorySelectScreen->menuCursorPos = ARRAY_COUNT(sSelect_MenuOptionFuncs) - 1; } gSprites[sFactorySelectScreen->menuCursor1SpriteId].pos1.y = (sFactorySelectScreen->menuCursorPos * 16) + 112; gSprites[sFactorySelectScreen->menuCursor2SpriteId].pos1.y = (sFactorySelectScreen->menuCursorPos * 16) + 112; } static void Select_UpdateYesNoCursorPosition(s8 direction) { if (direction > 0) // Move cursor down. { if (sFactorySelectScreen->yesNoCursorPos != 1) sFactorySelectScreen->yesNoCursorPos++; else sFactorySelectScreen->yesNoCursorPos = 0; } else // Move cursor up. { if (sFactorySelectScreen->yesNoCursorPos != 0) sFactorySelectScreen->yesNoCursorPos--; else sFactorySelectScreen->yesNoCursorPos = 1; } gSprites[sFactorySelectScreen->menuCursor1SpriteId].pos1.y = (sFactorySelectScreen->yesNoCursorPos * 16) + 112; gSprites[sFactorySelectScreen->menuCursor2SpriteId].pos1.y = (sFactorySelectScreen->yesNoCursorPos * 16) + 112; } static void Select_HandleMonSelectionChange(void) { u8 i, paletteNum; u8 cursorPos = sFactorySelectScreen->cursorPos; if (sFactorySelectScreen->mons[cursorPos].selectedId) // Deselect a mon. { paletteNum = IndexOfSpritePaletteTag(PALTAG_BALL_GRAY); if (sFactorySelectScreen->selectingMonsState == FRONTIER_PARTY_SIZE && sFactorySelectScreen->mons[cursorPos].selectedId == 1) { for (i = 0; i < SELECTABLE_MONS_COUNT; i++) { if (sFactorySelectScreen->mons[i].selectedId == FRONTIER_PARTY_SIZE - 1) break; } if (i == SELECTABLE_MONS_COUNT) return; else sFactorySelectScreen->mons[i].selectedId = 1; } sFactorySelectScreen->mons[cursorPos].selectedId = 0; sFactorySelectScreen->selectingMonsState--; } else // Select a mon. { paletteNum = IndexOfSpritePaletteTag(PALTAG_BALL_SELECTED); sFactorySelectScreen->mons[cursorPos].selectedId = sFactorySelectScreen->selectingMonsState; sFactorySelectScreen->selectingMonsState++; } gSprites[sFactorySelectScreen->mons[cursorPos].ballSpriteId].oam.paletteNum = paletteNum; } static void Select_SetBallSpritePaletteNum(u8 id) { u8 palNum; if (sFactorySelectScreen->mons[id].selectedId) palNum = IndexOfSpritePaletteTag(PALTAG_BALL_SELECTED); else palNum = IndexOfSpritePaletteTag(PALTAG_BALL_GRAY); gSprites[sFactorySelectScreen->mons[id].ballSpriteId].oam.paletteNum = palNum; } static void Select_Task_OpenSummaryScreen(u8 taskId) { u8 i; u8 currMonId; switch (gTasks[taskId].tState) { case STATE_SUMMARY_FADE: gPlttBufferUnfaded[228] = gPlttBufferFaded[228]; BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); gTasks[taskId].tState = STATE_SUMMARY_CLEAN; break; case STATE_SUMMARY_CLEAN: if (!gPaletteFade.active) { DestroyTask(sFactorySelectScreen->fadeSpeciesNameTaskId); HideMonPic(sFactorySelectScreen->monPics[1], &sFactorySelectScreen->monPicAnimating); Select_DestroyAllSprites(); FREE_AND_SET_NULL(sSelectMenuTilesetBuffer); FREE_AND_SET_NULL(sSelectMonPicBgTilesetBuffer); FREE_AND_SET_NULL(sSelectMenuTilemapBuffer); FREE_AND_SET_NULL(sSelectMonPicBgTilemapBuffer); FreeAllWindowBuffers(); gTasks[taskId].tState = STATE_SUMMARY_SHOW; } break; case STATE_SUMMARY_SHOW: sFactorySelectScreen->speciesNameColorBackup = gPlttBufferUnfaded[228]; DestroyTask(taskId); sFactorySelectScreen->fromSummaryScreen = TRUE; currMonId = sFactorySelectScreen->cursorPos; sFactorySelectMons = AllocZeroed(sizeof(struct Pokemon) * SELECTABLE_MONS_COUNT); for (i = 0; i < SELECTABLE_MONS_COUNT; i++) sFactorySelectMons[i] = sFactorySelectScreen->mons[i].monData; ShowPokemonSummaryScreen(PSS_MODE_LOCK_MOVES, sFactorySelectMons, currMonId, SELECTABLE_MONS_COUNT - 1, CB2_InitSelectScreen); break; } } static void Select_Task_Exit(u8 taskId) { if (sFactorySelectScreen->monPicAnimating == TRUE) return; switch (gTasks[taskId].tState) { case 0: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); gTasks[taskId].tState++; break; case 1: if (!UpdatePaletteFade()) { Select_CopyMonsToPlayerParty(); DestroyTask(sFactorySelectScreen->fadeSpeciesNameTaskId); Select_DestroyAllSprites(); FREE_AND_SET_NULL(sSelectMenuTilesetBuffer); FREE_AND_SET_NULL(sSelectMenuTilemapBuffer); FREE_AND_SET_NULL(sSelectMonPicBgTilemapBuffer); FREE_AND_SET_NULL(sFactorySelectScreen); FreeAllWindowBuffers(); SetMainCallback2(CB2_ReturnToFieldContinueScript); DestroyTask(taskId); } break; } } // Handles the Yes/No prompt when confirming the 3 selected rental pokemon static void Select_Task_HandleYesNo(u8 taskId) { if (sFactorySelectScreen->monPicAnimating == TRUE) return; switch (gTasks[taskId].tState) { case STATE_YESNO_SHOW_MONS: Select_ShowChosenMons(); gTasks[taskId].tState = STATE_YESNO_SHOW_OPTIONS; break; case STATE_YESNO_SHOW_OPTIONS: Select_ShowYesNoOptions(); gTasks[taskId].tState = STATE_YESNO_HANDLE_INPUT; break; case STATE_YESNO_HANDLE_INPUT: if (JOY_NEW(A_BUTTON)) { PlaySE(SE_SELECT); if (sFactorySelectScreen->yesNoCursorPos == 0) { // Selected Yes, confirmed selected pokemon Select_HideChosenMons(); gTasks[taskId].tState = 0; gTasks[taskId].func = Select_Task_Exit; } else { // Selected No, continue choosing pokemon Select_ErasePopupMenu(SELECT_WIN_YES_NO); Select_DeclineChosenMons(); sFactorySelectScreen->fadeSpeciesNameActive = TRUE; gTasks[taskId].tState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Select_Task_HandleChooseMons; } } else if (JOY_NEW(B_BUTTON)) { // Pressed B, Continue choosing pokemon PlaySE(SE_SELECT); Select_ErasePopupMenu(SELECT_WIN_YES_NO); Select_DeclineChosenMons(); sFactorySelectScreen->fadeSpeciesNameActive = TRUE; gTasks[taskId].tState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Select_Task_HandleChooseMons; } else if (JOY_REPEAT(DPAD_UP)) { PlaySE(SE_SELECT); Select_UpdateYesNoCursorPosition(-1); } else if (JOY_REPEAT(DPAD_DOWN)) { PlaySE(SE_SELECT); Select_UpdateYesNoCursorPosition(1); } break; } } // Handles the popup menu that shows when a pokemon is selected static void Select_Task_HandleMenu(u8 taskId) { switch (gTasks[taskId].tState) { case STATE_MENU_INIT: if (!sFactorySelectScreen->fromSummaryScreen) OpenMonPic(&sFactorySelectScreen->monPics[1].bgSpriteId, &sFactorySelectScreen->monPicAnimating, FALSE); gTasks[taskId].tState = STATE_MENU_SHOW_OPTIONS; break; case STATE_MENU_SHOW_OPTIONS: if (sFactorySelectScreen->monPicAnimating != TRUE) { Select_ShowMenuOptions(); sFactorySelectScreen->fromSummaryScreen = FALSE; gTasks[taskId].tState = STATE_MENU_HANDLE_INPUT; } break; case STATE_MENU_HANDLE_INPUT: if (JOY_NEW(A_BUTTON)) { u8 retVal; PlaySE(SE_SELECT); retVal = Select_RunMenuOptionFunc(); if (retVal == SELECT_CONTINUE_CHOOSING) { sFactorySelectScreen->fadeSpeciesNameActive = TRUE; gTasks[taskId].tState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Select_Task_HandleChooseMons; } else if (retVal == SELECT_CONFIRM_MONS) { gTasks[taskId].tState = STATE_YESNO_SHOW_MONS; gTasks[taskId].func = Select_Task_HandleYesNo; } else if (retVal == SELECT_INVALID_MON) { gTasks[taskId].tState = STATE_CHOOSE_MONS_INVALID; gTasks[taskId].func = Select_Task_HandleChooseMons; } else // SELECT_SUMMARY { gTasks[taskId].tState = STATE_SUMMARY_FADE; gTasks[taskId].func = Select_Task_OpenSummaryScreen; } } else if (JOY_NEW(B_BUTTON)) { PlaySE(SE_SELECT); CloseMonPic(sFactorySelectScreen->monPics[1], &sFactorySelectScreen->monPicAnimating, FALSE); Select_ErasePopupMenu(SELECT_WIN_OPTIONS); sFactorySelectScreen->fadeSpeciesNameActive = TRUE; gTasks[taskId].tState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Select_Task_HandleChooseMons; } else if (JOY_REPEAT(DPAD_UP)) { PlaySE(SE_SELECT); Select_UpdateMenuCursorPosition(-1); } else if (JOY_REPEAT(DPAD_DOWN)) { PlaySE(SE_SELECT); Select_UpdateMenuCursorPosition(1); } break; case STATE_MENU_REINIT: if (!gPaletteFade.active) { if (sFactorySelectScreen->fromSummaryScreen == TRUE) { gPlttBufferFaded[228] = sFactorySelectScreen->speciesNameColorBackup; gPlttBufferUnfaded[228] = gPlttBufferUnfaded[244]; } sFactorySelectScreen->fromSummaryScreen = FALSE; gTasks[taskId].tState = STATE_MENU_HANDLE_INPUT; } break; case STATE_MENU_RESHOW: Select_ShowMenuOptions(); gTasks[taskId].tState = STATE_MENU_REINIT; break; } } // Handles input on the main selection screen, when no popup menu is open static void Select_Task_HandleChooseMons(u8 taskId) { if (sFactorySelectScreen->monPicAnimating == TRUE) return; switch (gTasks[taskId].tState) { case STATE_CHOOSE_MONS_INIT: if (!gPaletteFade.active) { gTasks[taskId].tState = STATE_CHOOSE_MONS_HANDLE_INPUT; sFactorySelectScreen->fadeSpeciesNameActive = TRUE; } break; case STATE_CHOOSE_MONS_HANDLE_INPUT: if (JOY_NEW(A_BUTTON)) { PlaySE(SE_SELECT); sFactorySelectScreen->fadeSpeciesNameActive = FALSE; gTasks[taskId].tState = STATE_MENU_INIT; gTasks[taskId].func = Select_Task_HandleMenu; } else if (JOY_REPEAT(DPAD_LEFT)) { PlaySE(SE_SELECT); Select_UpdateBallCursorPosition(-1); Select_PrintMonCategory(); Select_PrintMonSpecies(); } else if (JOY_REPEAT(DPAD_RIGHT)) { PlaySE(SE_SELECT); Select_UpdateBallCursorPosition(1); Select_PrintMonCategory(); Select_PrintMonSpecies(); } break; case STATE_CHOOSE_MONS_INVALID: if (JOY_NEW(A_BUTTON)) { PlaySE(SE_SELECT); CloseMonPic(sFactorySelectScreen->monPics[1], &sFactorySelectScreen->monPicAnimating, FALSE); Select_PrintSelectMonString(); sFactorySelectScreen->fadeSpeciesNameActive = TRUE; gTasks[taskId].tState = STATE_CHOOSE_MONS_HANDLE_INPUT; } break; } } #undef STATE_CHOOSE_MONS_INIT #undef STATE_CHOOSE_MONS_HANDLE_INPUT #undef STATE_MENU_INIT #undef STATE_MENU_HANDLE_INPUT #undef STATE_YESNO_SHOW_OPTIONS #undef STATE_YESNO_HANDLE_INPUT #undef STATE_SUMMARY_FADE #undef STATE_SUMMARY_CLEAN #undef STATE_SUMMARY_SHOW #undef STATE_MENU_SHOW_OPTIONS #undef STATE_YESNO_SHOW_MONS #undef STATE_CHOOSE_MONS_INVALID #undef STATE_MENU_REINIT #undef STATE_MENU_RESHOW static void CreateFrontierFactorySelectableMons(u8 firstMonId) { u8 i, j = 0; u8 ivs = 0; u8 level = 0; u8 friendship = 0; u32 otId = 0; u8 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE); u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode; u8 challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7; u8 rentalRank = 0; gFacilityTrainerMons = gBattleFrontierMons; if (gSaveBlock2Ptr->frontier.lvlMode != FRONTIER_LVL_50) level = 100; else level = 50; rentalRank = GetNumPastRentalsRank(battleMode, lvlMode); otId = T1_READ_32(gSaveBlock2Ptr->playerTrainerId); for (i = 0; i < SELECTABLE_MONS_COUNT; i++) { u16 monId = gSaveBlock2Ptr->frontier.rentalMons[i].monId; sFactorySelectScreen->mons[i + firstMonId].monId = monId; if (i < rentalRank) ivs = GetFactoryMonFixedIV(challengeNum + 1, 0); else ivs = GetFactoryMonFixedIV(challengeNum, 0); CreateMonWithEVSpreadNatureOTID(&sFactorySelectScreen->mons[i + firstMonId].monData, gFacilityTrainerMons[monId].species, level, gFacilityTrainerMons[monId].nature, ivs, gFacilityTrainerMons[monId].evSpread, otId); friendship = 0; for (j = 0; j < MAX_MON_MOVES; j++) SetMonMoveAvoidReturn(&sFactorySelectScreen->mons[i + firstMonId].monData, gFacilityTrainerMons[monId].moves[j], j); SetMonData(&sFactorySelectScreen->mons[i + firstMonId].monData, MON_DATA_FRIENDSHIP, &friendship); SetMonData(&sFactorySelectScreen->mons[i + firstMonId].monData, MON_DATA_HELD_ITEM, &gBattleFrontierHeldItems[gFacilityTrainerMons[monId].itemTableId]); } } static void CreateSlateportTentSelectableMons(u8 firstMonId) { u8 i, j; u8 ivs = 0; u8 level = 30; u8 friendship = 0; u32 otId = 0; gFacilityTrainerMons = gSlateportBattleTentMons; otId = T1_READ_32(gSaveBlock2Ptr->playerTrainerId); for (i = 0; i < SELECTABLE_MONS_COUNT; i++) { u16 monId = gSaveBlock2Ptr->frontier.rentalMons[i].monId; sFactorySelectScreen->mons[i + firstMonId].monId = monId; CreateMonWithEVSpreadNatureOTID(&sFactorySelectScreen->mons[i + firstMonId].monData, gFacilityTrainerMons[monId].species, level, gFacilityTrainerMons[monId].nature, ivs, gFacilityTrainerMons[monId].evSpread, otId); friendship = 0; for (j = 0; j < MAX_MON_MOVES; j++) SetMonMoveAvoidReturn(&sFactorySelectScreen->mons[i + firstMonId].monData, gFacilityTrainerMons[monId].moves[j], j); SetMonData(&sFactorySelectScreen->mons[i + firstMonId].monData, MON_DATA_FRIENDSHIP, &friendship); SetMonData(&sFactorySelectScreen->mons[i + firstMonId].monData, MON_DATA_HELD_ITEM, &gBattleFrontierHeldItems[gFacilityTrainerMons[monId].itemTableId]); } } static void Select_CopyMonsToPlayerParty(void) { u8 i, j; for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { for (j = 0; j < SELECTABLE_MONS_COUNT; j++) { if (sFactorySelectScreen->mons[j].selectedId == i + 1) { gPlayerParty[i] = sFactorySelectScreen->mons[j].monData; gSaveBlock2Ptr->frontier.rentalMons[i].monId = sFactorySelectScreen->mons[j].monId; gSaveBlock2Ptr->frontier.rentalMons[i].personality = GetMonData(&gPlayerParty[i], MON_DATA_PERSONALITY, NULL); gSaveBlock2Ptr->frontier.rentalMons[i].abilityNum = GetBoxMonData(&gPlayerParty[i].box, MON_DATA_ABILITY_NUM, NULL); gSaveBlock2Ptr->frontier.rentalMons[i].ivs = GetBoxMonData(&gPlayerParty[i].box, MON_DATA_ATK_IV, NULL); break; } } } CalculatePlayerPartyCount(); } static void Select_ShowMenuOptions(void) { if (!sFactorySelectScreen->fromSummaryScreen) sFactorySelectScreen->menuCursorPos = 0; gSprites[sFactorySelectScreen->menuCursor1SpriteId].pos1.x = 176; gSprites[sFactorySelectScreen->menuCursor1SpriteId].pos1.y = (sFactorySelectScreen->menuCursorPos * 16) + 112; gSprites[sFactorySelectScreen->menuCursor2SpriteId].pos1.x = 208; gSprites[sFactorySelectScreen->menuCursor2SpriteId].pos1.y = (sFactorySelectScreen->menuCursorPos * 16) + 112; gSprites[sFactorySelectScreen->menuCursor1SpriteId].invisible = FALSE; gSprites[sFactorySelectScreen->menuCursor2SpriteId].invisible = FALSE; Select_PrintMenuOptions(); } static void Select_ShowYesNoOptions(void) { sFactorySelectScreen->yesNoCursorPos = 0; gSprites[sFactorySelectScreen->menuCursor1SpriteId].pos1.x = 176; gSprites[sFactorySelectScreen->menuCursor1SpriteId].pos1.y = 112; gSprites[sFactorySelectScreen->menuCursor2SpriteId].pos1.x = 208; gSprites[sFactorySelectScreen->menuCursor2SpriteId].pos1.y = 112; gSprites[sFactorySelectScreen->menuCursor1SpriteId].invisible = FALSE; gSprites[sFactorySelectScreen->menuCursor2SpriteId].invisible = FALSE; Select_PrintYesNoOptions(); } static void Select_ErasePopupMenu(u8 windowId) { gSprites[sFactorySelectScreen->menuCursor1SpriteId].invisible = TRUE; gSprites[sFactorySelectScreen->menuCursor2SpriteId].invisible = TRUE; FillWindowPixelBuffer(windowId, PIXEL_FILL(0)); CopyWindowToVram(windowId, 2); ClearWindowTilemap(windowId); } static void Select_PrintRentalPkmnString(void) { FillWindowPixelBuffer(SELECT_WIN_TITLE, PIXEL_FILL(0)); AddTextPrinterParameterized(SELECT_WIN_TITLE, 1, gText_RentalPkmn2, 2, 1, 0, NULL); CopyWindowToVram(SELECT_WIN_TITLE, 3); } static void Select_PrintMonSpecies(void) { u16 species; u8 x; u8 monId = sFactorySelectScreen->cursorPos; FillWindowPixelBuffer(SELECT_WIN_SPECIES, PIXEL_FILL(0)); species = GetMonData(&sFactorySelectScreen->mons[monId].monData, MON_DATA_SPECIES, NULL); StringCopy(gStringVar4, gSpeciesNames[species]); x = GetStringRightAlignXOffset(1, gStringVar4, 86); AddTextPrinterParameterized3(SELECT_WIN_SPECIES, 1, x, 1, sSpeciesNameTextColors, 0, gStringVar4); CopyWindowToVram(SELECT_WIN_SPECIES, 2); } static void Select_PrintSelectMonString(void) { const u8 *str = NULL; FillWindowPixelBuffer(SELECT_WIN_INFO, PIXEL_FILL(0)); if (sFactorySelectScreen->selectingMonsState == 1) str = gText_SelectFirstPkmn; else if (sFactorySelectScreen->selectingMonsState == 2) str = gText_SelectSecondPkmn; else if (sFactorySelectScreen->selectingMonsState == 3) str = gText_SelectThirdPkmn; else str = gText_TheseThreePkmnOkay; AddTextPrinterParameterized(SELECT_WIN_INFO, 1, str, 2, 5, 0, NULL); CopyWindowToVram(SELECT_WIN_INFO, 2); } static void Select_PrintCantSelectSameMon(void) { FillWindowPixelBuffer(SELECT_WIN_INFO, PIXEL_FILL(0)); AddTextPrinterParameterized(SELECT_WIN_INFO, 1, gText_CantSelectSamePkmn, 2, 5, 0, NULL); CopyWindowToVram(SELECT_WIN_INFO, 2); } static void Select_PrintMenuOptions(void) { u8 selectedId = sFactorySelectScreen->mons[sFactorySelectScreen->cursorPos].selectedId; PutWindowTilemap(SELECT_WIN_OPTIONS); FillWindowPixelBuffer(SELECT_WIN_OPTIONS, PIXEL_FILL(0)); AddTextPrinterParameterized3(SELECT_WIN_OPTIONS, 1, 7, 1, sMenuOptionTextColors, 0, gText_Summary); if (selectedId != 0) AddTextPrinterParameterized3(SELECT_WIN_OPTIONS, 1, 7, 17, sMenuOptionTextColors, 0, gText_Deselect); else AddTextPrinterParameterized3(SELECT_WIN_OPTIONS, 1, 7, 17, sMenuOptionTextColors, 0, gText_Rent); AddTextPrinterParameterized3(SELECT_WIN_OPTIONS, 1, 7, 33, sMenuOptionTextColors, 0, gText_Others2); CopyWindowToVram(SELECT_WIN_OPTIONS, 3); } static void Select_PrintYesNoOptions(void) { PutWindowTilemap(SELECT_WIN_YES_NO); FillWindowPixelBuffer(SELECT_WIN_YES_NO, PIXEL_FILL(0)); AddTextPrinterParameterized3(SELECT_WIN_YES_NO, 1, 7, 1, sMenuOptionTextColors, 0, gText_Yes2); AddTextPrinterParameterized3(SELECT_WIN_YES_NO, 1, 7, 17, sMenuOptionTextColors, 0, gText_No2); CopyWindowToVram(SELECT_WIN_YES_NO, 3); } static u8 Select_RunMenuOptionFunc(void) { gFactorySelect_CurrentOptionFunc = sSelect_MenuOptionFuncs[sFactorySelectScreen->menuCursorPos]; return gFactorySelect_CurrentOptionFunc(); } static u8 Select_OptionRentDeselect(void) { u8 selectedId = sFactorySelectScreen->mons[sFactorySelectScreen->cursorPos].selectedId; u16 monId = sFactorySelectScreen->mons[sFactorySelectScreen->cursorPos].monId; if (selectedId == 0 && !Select_AreSpeciesValid(monId)) { Select_PrintCantSelectSameMon(); Select_ErasePopupMenu(SELECT_WIN_OPTIONS); return SELECT_INVALID_MON; } else { CloseMonPic(sFactorySelectScreen->monPics[1], &sFactorySelectScreen->monPicAnimating, FALSE); Select_HandleMonSelectionChange(); Select_PrintSelectMonString(); Select_ErasePopupMenu(SELECT_WIN_OPTIONS); if (sFactorySelectScreen->selectingMonsState > FRONTIER_PARTY_SIZE) return SELECT_CONFIRM_MONS; else return SELECT_CONTINUE_CHOOSING; } } static u8 Select_DeclineChosenMons(void) { Select_HideChosenMons(); Select_HandleMonSelectionChange(); Select_PrintSelectMonString(); Select_ErasePopupMenu(SELECT_WIN_OPTIONS); if (sFactorySelectScreen->selectingMonsState > FRONTIER_PARTY_SIZE) return 2; else return 1; } static u8 Select_OptionSummary(void) { return SELECT_SUMMARY; } static u8 Select_OptionOthers(void) { CloseMonPic(sFactorySelectScreen->monPics[1], &sFactorySelectScreen->monPicAnimating, FALSE); Select_ErasePopupMenu(SELECT_WIN_OPTIONS); return SELECT_CONTINUE_CHOOSING; } static void Select_PrintMonCategory(void) { u16 species; u8 text[30]; u8 x; u8 monId = sFactorySelectScreen->cursorPos; if (monId < SELECTABLE_MONS_COUNT) { PutWindowTilemap(SELECT_WIN_MON_CATEGORY); FillWindowPixelBuffer(SELECT_WIN_MON_CATEGORY, PIXEL_FILL(0)); species = GetMonData(&sFactorySelectScreen->mons[monId].monData, MON_DATA_SPECIES, NULL); CopyMonCategoryText(SpeciesToNationalPokedexNum(species), text); x = GetStringRightAlignXOffset(1, text, 0x76); AddTextPrinterParameterized(SELECT_WIN_MON_CATEGORY, 1, text, x, 1, 0, NULL); CopyWindowToVram(SELECT_WIN_MON_CATEGORY, 2); } } static void Select_CreateMonSprite(void) { u8 monId = sFactorySelectScreen->cursorPos; struct Pokemon *mon = &sFactorySelectScreen->mons[monId].monData; u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL); u32 otId = GetMonData(mon, MON_DATA_OT_ID, NULL); sFactorySelectScreen->monPics[1].monSpriteId = CreateMonPicSprite_HandleDeoxys(species, otId, personality, TRUE, 88, 32, 15, 0xFFFF); gSprites[sFactorySelectScreen->monPics[1].monSpriteId].centerToCornerVecX = 0; gSprites[sFactorySelectScreen->monPics[1].monSpriteId].centerToCornerVecY = 0; sFactorySelectScreen->monPicAnimating = FALSE; } static void Select_SetMonPicAnimating(bool8 animating) { sFactorySelectScreen->monPicAnimating = animating; } static void Select_ReshowMonSprite(void) { struct Pokemon *mon; u16 species; u32 personality, otId; sFactorySelectScreen->monPics[1].bgSpriteId = CreateSprite(&sSpriteTemplate_Select_MonPicBgAnim, 120, 64, 1); StartSpriteAffineAnim(&gSprites[sFactorySelectScreen->monPics[1].bgSpriteId], 2); mon = &sFactorySelectScreen->mons[sFactorySelectScreen->cursorPos].monData; species = GetMonData(mon, MON_DATA_SPECIES, NULL); personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL); otId = GetMonData(mon, MON_DATA_OT_ID, NULL); sFactorySelectScreen->monPics[1].monSpriteId = CreateMonPicSprite_HandleDeoxys(species, otId, personality, TRUE, 88, 32, 15, 0xFFFF); gSprites[sFactorySelectScreen->monPics[1].monSpriteId].centerToCornerVecX = 0; gSprites[sFactorySelectScreen->monPics[1].monSpriteId].centerToCornerVecY = 0; gSprites[sFactorySelectScreen->monPics[1].bgSpriteId].invisible = TRUE; } static void Select_CreateChosenMonsSprites(void) { u8 i, j; for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { for (j = 0; j < SELECTABLE_MONS_COUNT; j++) { if (sFactorySelectScreen->mons[j].selectedId == i + 1) { struct Pokemon *mon = &sFactorySelectScreen->mons[j].monData; u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL); u32 otId = GetMonData(mon, MON_DATA_OT_ID, NULL); sFactorySelectScreen->monPics[i].monSpriteId = CreateMonPicSprite_HandleDeoxys(species, otId, personality, TRUE, (i * 72) + 16, 32, i + 13, 0xFFFF); gSprites[sFactorySelectScreen->monPics[i].monSpriteId].centerToCornerVecX = 0; gSprites[sFactorySelectScreen->monPics[i].monSpriteId].centerToCornerVecY = 0; break; } } } sFactorySelectScreen->monPicAnimating = FALSE; } static void SpriteCB_OpenChosenMonPics(struct Sprite *sprite) { u8 taskId; // Current sprite is monPics[1] if (sprite->affineAnimEnded && gSprites[sFactorySelectScreen->monPics[0].bgSpriteId].affineAnimEnded && gSprites[sFactorySelectScreen->monPics[2].bgSpriteId].affineAnimEnded) { sprite->invisible = TRUE; gSprites[sFactorySelectScreen->monPics[0].bgSpriteId].invisible = TRUE; gSprites[sFactorySelectScreen->monPics[2].bgSpriteId].invisible = TRUE; taskId = CreateTask(Select_Task_OpenChosenMonPics, 1); gTasks[taskId].func(taskId); sprite->callback = SpriteCallbackDummy; } } static void SpriteCB_CloseChosenMonPics(struct Sprite *sprite) { // Current sprite is monPics[1] if (sprite->affineAnimEnded && gSprites[sFactorySelectScreen->monPics[0].bgSpriteId].affineAnimEnded && gSprites[sFactorySelectScreen->monPics[2].bgSpriteId].affineAnimEnded) { FreeOamMatrix(sprite->oam.matrixNum); FreeOamMatrix(gSprites[sFactorySelectScreen->monPics[0].bgSpriteId].oam.matrixNum); FreeOamMatrix(gSprites[sFactorySelectScreen->monPics[2].bgSpriteId].oam.matrixNum); sFactorySelectScreen->monPicAnimating = FALSE; DestroySprite(&gSprites[sFactorySelectScreen->monPics[0].bgSpriteId]); DestroySprite(&gSprites[sFactorySelectScreen->monPics[2].bgSpriteId]); DestroySprite(sprite); } } // Task data for Select_Task_OpenChosenMonPics, Select_Task_CloseChosenMonPics, Task_CloseMonPic, and Task_OpenMonPic #define tWinLeft data[3] #ifndef UBFIX #define tWinRight data[24] // UB: Typo? Likely meant data[4], 24 is out of bounds #else #define tWinRight data[4] #endif #define tWinTop data[5] #define tWinBottom data[8] #define tSpriteId data[6] // TODO: Clarify, what sprite #define tIsSwapScreen data[7] static void Select_Task_OpenChosenMonPics(u8 taskId) { struct Task *task = &gTasks[taskId]; switch (task->tState) { case 0: task->tWinLeft = 16; task->tWinRight = DISPLAY_WIDTH - 16; task->tWinTop = 64; task->tWinBottom = 65; SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(task->tWinLeft, task->tWinRight)); SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom)); SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ); SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG2 | WINOUT_WIN01_CLR | WINOUT_WIN01_OBJ); break; case 1: ShowBg(3); SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG3 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_OBJ); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(11, 4)); break; case 2: task->tWinTop -= 4; task->tWinBottom += 4; if (task->tWinTop <= 32 || task->tWinBottom >= 96) { task->tWinTop = 32; task->tWinBottom = 96; ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); } SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom)); if (task->tWinTop != 32) return; break; default: DestroyTask(taskId); Select_CreateChosenMonsSprites(); return; } task->tState++; } static void Select_Task_CloseChosenMonPics(u8 taskId) { struct Task *task = &gTasks[taskId]; switch (task->tState) { case 0: task->tWinLeft = 16; task->tWinRight = DISPLAY_WIDTH - 16; task->tWinTop = 32; task->tWinBottom = 96; SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(task->tWinLeft, task->tWinRight)); SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom)); SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ); SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG2 | WINOUT_WIN01_CLR | WINOUT_WIN01_OBJ); task->tState++; break; case 1: task->tWinTop += 4; task->tWinBottom -= 4; if (task->tWinTop >= 64 || task->tWinBottom <= 65) { task->tWinTop = 64; task->tWinBottom = 65; } SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom)); if (task->tWinTop == 64) task->tState++; break; default: HideBg(3); gSprites[sFactorySelectScreen->monPics[1].bgSpriteId].invisible = FALSE; gSprites[sFactorySelectScreen->monPics[1].bgSpriteId].callback = SpriteCB_CloseChosenMonPics; gSprites[sFactorySelectScreen->monPics[0].bgSpriteId].invisible = FALSE; gSprites[sFactorySelectScreen->monPics[0].bgSpriteId].callback = SpriteCallbackDummy; gSprites[sFactorySelectScreen->monPics[2].bgSpriteId].invisible = FALSE; gSprites[sFactorySelectScreen->monPics[2].bgSpriteId].callback = SpriteCallbackDummy; StartSpriteAffineAnim(&gSprites[sFactorySelectScreen->monPics[1].bgSpriteId], 1); StartSpriteAffineAnim(&gSprites[sFactorySelectScreen->monPics[0].bgSpriteId], 1); StartSpriteAffineAnim(&gSprites[sFactorySelectScreen->monPics[2].bgSpriteId], 1); ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); DestroyTask(taskId); break; } } static void Select_ShowChosenMons(void) { sFactorySelectScreen->monPics[1].bgSpriteId = CreateSprite(&sSpriteTemplate_Select_MonPicBgAnim, 120, 64, 1); sFactorySelectScreen->monPics[0].bgSpriteId = CreateSprite(&sSpriteTemplate_Select_MonPicBgAnim, 44, 64, 1); sFactorySelectScreen->monPics[2].bgSpriteId = CreateSprite(&sSpriteTemplate_Select_MonPicBgAnim, 196, 64, 1); gSprites[sFactorySelectScreen->monPics[1].bgSpriteId].callback = SpriteCB_OpenChosenMonPics; gSprites[sFactorySelectScreen->monPics[0].bgSpriteId].callback = SpriteCallbackDummy; gSprites[sFactorySelectScreen->monPics[2].bgSpriteId].callback = SpriteCallbackDummy; sFactorySelectScreen->monPicAnimating = TRUE; } static void Select_HideChosenMons(void) { u8 taskId; FreeAndDestroyMonPicSprite(sFactorySelectScreen->monPics[0].monSpriteId); FreeAndDestroyMonPicSprite(sFactorySelectScreen->monPics[1].monSpriteId); FreeAndDestroyMonPicSprite(sFactorySelectScreen->monPics[2].monSpriteId); taskId = CreateTask(Select_Task_CloseChosenMonPics, 1); gTasks[taskId].func(taskId); sFactorySelectScreen->monPicAnimating = TRUE; } static void Select_SetWinRegs(s16 mWin0H, s16 nWin0H, s16 mWin0V, s16 nWin0V) { SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(mWin0H, nWin0H)); SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(mWin0V, nWin0V)); SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ); SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG2 | WINOUT_WIN01_CLR | WINOUT_WIN01_OBJ); } static bool32 Select_AreSpeciesValid(u16 monId) { u8 i, j; u32 species = gFacilityTrainerMons[monId].species; u8 selectState = sFactorySelectScreen->selectingMonsState; for (i = 1; i < selectState; i++) { for (j = 0; j < SELECTABLE_MONS_COUNT; j++) { if (sFactorySelectScreen->mons[j].selectedId == i) { if (gFacilityTrainerMons[sFactorySelectScreen->mons[j].monId].species == species) return FALSE; break; } } } return TRUE; } static void Select_Task_FadeSpeciesName(u8 taskId) { switch (gTasks[taskId].tState) { case FADESTATE_INIT: sFactorySelectScreen->fadeSpeciesNameCoeffDelay = 0; sFactorySelectScreen->fadeSpeciesNameCoeff = 0; sFactorySelectScreen->fadeSpeciesNameFadeOut = TRUE; gTasks[taskId].tState = FADESTATE_RUN; break; case FADESTATE_RUN: if (sFactorySelectScreen->fadeSpeciesNameActive) { if (sFactorySelectScreen->faceSpeciesNameDelay) { gTasks[taskId].tState = FADESTATE_DELAY; } else { sFactorySelectScreen->fadeSpeciesNameCoeffDelay++; if (sFactorySelectScreen->fadeSpeciesNameCoeffDelay > 6) { sFactorySelectScreen->fadeSpeciesNameCoeffDelay = 0; if (!sFactorySelectScreen->fadeSpeciesNameFadeOut) sFactorySelectScreen->fadeSpeciesNameCoeff--; else sFactorySelectScreen->fadeSpeciesNameCoeff++; } BlendPalettes(0x4000, sFactorySelectScreen->fadeSpeciesNameCoeff, 0); if (sFactorySelectScreen->fadeSpeciesNameCoeff > 5) { sFactorySelectScreen->fadeSpeciesNameFadeOut = FALSE; } else if (sFactorySelectScreen->fadeSpeciesNameCoeff == 0) { gTasks[taskId].tState = FADESTATE_DELAY; sFactorySelectScreen->fadeSpeciesNameFadeOut = TRUE; } } } break; case FADESTATE_DELAY: if (sFactorySelectScreen->faceSpeciesNameDelay > 14) { sFactorySelectScreen->faceSpeciesNameDelay = 0; gTasks[taskId].tState = FADESTATE_RUN; } else { sFactorySelectScreen->faceSpeciesNameDelay++; } break; } } // Swap Screen's section begins here. static void Swap_CB2(void) { AnimateSprites(); BuildOamBuffer(); RunTextPrinters(); UpdatePaletteFade(); RunTasks(); } static void Swap_VblankCb(void) { LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); } static void CopySwappedMonData(void) { u8 friendship; gPlayerParty[sFactorySwapScreen->playerMonId] = gEnemyParty[sFactorySwapScreen->enemyMonId]; friendship = 0; SetMonData(&gPlayerParty[sFactorySwapScreen->playerMonId], MON_DATA_FRIENDSHIP, &friendship); gSaveBlock2Ptr->frontier.rentalMons[sFactorySwapScreen->playerMonId].monId = gSaveBlock2Ptr->frontier.rentalMons[sFactorySwapScreen->enemyMonId + FRONTIER_PARTY_SIZE].monId; gSaveBlock2Ptr->frontier.rentalMons[sFactorySwapScreen->playerMonId].ivs = gSaveBlock2Ptr->frontier.rentalMons[sFactorySwapScreen->enemyMonId + FRONTIER_PARTY_SIZE].ivs; gSaveBlock2Ptr->frontier.rentalMons[sFactorySwapScreen->playerMonId].personality = GetMonData(&gEnemyParty[sFactorySwapScreen->enemyMonId], MON_DATA_PERSONALITY, NULL); gSaveBlock2Ptr->frontier.rentalMons[sFactorySwapScreen->playerMonId].abilityNum = GetBoxMonData(&gEnemyParty[sFactorySwapScreen->enemyMonId].box, MON_DATA_ABILITY_NUM, NULL); } // Main swap states // States for the main tasks of the Swap_ functions after initialization, including: // Swap_Task_OpenSummaryScreen, Swap_Task_HandleYesNo, Swap_Task_HandleMenu, and Swap_Task_HandleChooseMons // Tasks sharing states was unnecessary, see "Main select states" #define STATE_CHOOSE_MONS_INIT 0 #define STATE_CHOOSE_MONS_HANDLE_INPUT 1 #define STATE_MENU_INIT 2 #define STATE_MENU_HANDLE_INPUT 3 #define STATE_YESNO_SHOW 4 #define STATE_YESNO_HANDLE_INPUT 5 #define STATE_SUMMARY_FADE 6 #define STATE_SUMMARY_CLEAN 7 #define STATE_SUMMARY_SHOW 8 #define STATE_MENU_SHOW_OPTIONS 9 static void Swap_Task_OpenSummaryScreen(u8 taskId) { switch (gTasks[taskId].tState) { case STATE_SUMMARY_FADE: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); gTasks[taskId].tState = STATE_SUMMARY_CLEAN; break; case STATE_SUMMARY_CLEAN: if (!gPaletteFade.active) { DestroyTask(sFactorySwapScreen->fadeSpeciesNameTaskId); HideMonPic(sFactorySwapScreen->monPic, &sFactorySwapScreen->monPicAnimating); Swap_DestroyAllSprites(); FREE_AND_SET_NULL(sSwapMenuTilesetBuffer); FREE_AND_SET_NULL(sSwapMonPicBgTilesetBuffer); FREE_AND_SET_NULL(sSwapMenuTilemapBuffer); FREE_AND_SET_NULL(sSwapMonPicBgTilemapBuffer); FreeAllWindowBuffers(); gTasks[taskId].tState = STATE_SUMMARY_SHOW; } break; case STATE_SUMMARY_SHOW: DestroyTask(taskId); sFactorySwapScreen->fromSummaryScreen = TRUE; sFactorySwapScreen->speciesNameColorBackup = gPlttBufferUnfaded[244]; ShowPokemonSummaryScreen(PSS_MODE_NORMAL, gPlayerParty, sFactorySwapScreen->cursorPos, FRONTIER_PARTY_SIZE - 1, CB2_InitSwapScreen); break; } } static void Swap_Task_Exit(u8 taskId) { if (sFactorySwapScreen->monPicAnimating == TRUE) return; switch (gTasks[taskId].tState) { case 0: // Set return value for script // TRUE if player kept their current pokemon if (sFactorySwapScreen->monSwapped == TRUE) { gTasks[taskId].tState++; gSpecialVar_Result = FALSE; } else { gTasks[taskId].tState = 2; gSpecialVar_Result = TRUE; } break; case 1: if (sFactorySwapScreen->monSwapped == TRUE) { sFactorySwapScreen->enemyMonId = sFactorySwapScreen->cursorPos; CopySwappedMonData(); } gTasks[taskId].tState++; break; case 2: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); gTasks[taskId].tState++; break; case 3: if (!UpdatePaletteFade()) { DestroyTask(sFactorySwapScreen->fadeSpeciesNameTaskId); Swap_DestroyAllSprites(); FREE_AND_SET_NULL(sSwapMenuTilesetBuffer); FREE_AND_SET_NULL(sSwapMonPicBgTilesetBuffer); FREE_AND_SET_NULL(sSwapMenuTilemapBuffer); FREE_AND_SET_NULL(sSwapMonPicBgTilemapBuffer); FREE_AND_SET_NULL(sFactorySwapScreen); FreeAllWindowBuffers(); SetMainCallback2(CB2_ReturnToFieldContinueScript); DestroyTask(taskId); } break; } } #define tSaidYes data[1] #define tFollowUpTaskState data[5] #define tFollowUpTaskPtrHi data[6] #define tFollowUpTaskPtrLo data[7] static void Swap_Task_HandleYesNo(u8 taskId) { u16 loPtr, hiPtr; if (sFactorySwapScreen->monPicAnimating == TRUE) return; switch (gTasks[taskId].tState) { case STATE_YESNO_SHOW: Swap_ShowYesNoOptions(); gTasks[taskId].tState = STATE_YESNO_HANDLE_INPUT; break; case STATE_YESNO_HANDLE_INPUT: if (JOY_NEW(A_BUTTON)) { PlaySE(SE_SELECT); if (sFactorySwapScreen->yesNoCursorPos == 0) { // Selected Yes gTasks[taskId].tSaidYes = TRUE; hiPtr = gTasks[taskId].tFollowUpTaskPtrHi; loPtr = gTasks[taskId].tFollowUpTaskPtrLo; gTasks[taskId].func = (void*)((hiPtr << 16) | loPtr); } else { // Selected No gTasks[taskId].tSaidYes = FALSE; Swap_ErasePopupMenu(SWAP_WIN_YES_NO); hiPtr = gTasks[taskId].tFollowUpTaskPtrHi; loPtr = gTasks[taskId].tFollowUpTaskPtrLo; gTasks[taskId].func = (void*)((hiPtr << 16) | loPtr); } } else if (JOY_NEW(B_BUTTON)) { PlaySE(SE_SELECT); gTasks[taskId].tSaidYes = FALSE; Swap_ErasePopupMenu(SWAP_WIN_YES_NO); hiPtr = gTasks[taskId].tFollowUpTaskPtrHi; loPtr = gTasks[taskId].tFollowUpTaskPtrLo; gTasks[taskId].func = (void*)((hiPtr << 16) | loPtr); } else if (JOY_REPEAT(DPAD_UP)) { PlaySE(SE_SELECT); Swap_UpdateYesNoCursorPosition(-1); } else if (JOY_REPEAT(DPAD_DOWN)) { PlaySE(SE_SELECT); Swap_UpdateYesNoCursorPosition(1); } break; } } static void Swap_HandleQuitSwappingResposne(u8 taskId) { if (gTasks[taskId].tSaidYes == TRUE) { gTasks[taskId].tState = 0; gTasks[taskId].func = Swap_Task_Exit; } else { gTasks[taskId].tState = 0; gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_Task_HandleChooseMons) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_Task_HandleChooseMons); gTasks[taskId].tFollowUpTaskState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Swap_Task_ScreenInfoTransitionIn; } } static void Swap_AskQuitSwapping(u8 taskId) { if (gTasks[taskId].tState == 0) { Swap_PrintOnInfoWindow(gText_QuitSwapping); sFactorySwapScreen->monSwapped = FALSE; gTasks[taskId].tState = STATE_YESNO_SHOW; gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_HandleQuitSwappingResposne) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_HandleQuitSwappingResposne); gTasks[taskId].func = Swap_Task_HandleYesNo; } } static void Swap_HandleAcceptMonResponse(u8 taskId) { CloseMonPic(sFactorySwapScreen->monPic, &sFactorySwapScreen->monPicAnimating, TRUE); if (gTasks[taskId].tSaidYes == TRUE) { gTasks[taskId].tState = 0; gTasks[taskId].func = Swap_Task_Exit; } else { gTasks[taskId].tState = 0; gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_Task_HandleChooseMons) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_Task_HandleChooseMons); gTasks[taskId].tFollowUpTaskState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Swap_Task_ScreenInfoTransitionIn; } } static void Swap_AskAcceptMon(u8 taskId) { if (gTasks[taskId].tState == 0) { OpenMonPic(&sFactorySwapScreen->monPic.bgSpriteId, &sFactorySwapScreen->monPicAnimating, TRUE); Swap_PrintOnInfoWindow(gText_AcceptThisPkmn); sFactorySwapScreen->monSwapped = TRUE; gTasks[taskId].tState = STATE_YESNO_SHOW; gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_HandleAcceptMonResponse) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_HandleAcceptMonResponse); gTasks[taskId].func = Swap_Task_HandleYesNo; } } static void Swap_Task_HandleMenu(u8 taskId) { switch (gTasks[taskId].tState) { case STATE_MENU_INIT: if (!sFactorySwapScreen->fromSummaryScreen) OpenMonPic(&sFactorySwapScreen->monPic.bgSpriteId, &sFactorySwapScreen->monPicAnimating, TRUE); gTasks[taskId].tState = STATE_MENU_SHOW_OPTIONS; break; case STATE_MENU_SHOW_OPTIONS: if (sFactorySwapScreen->monPicAnimating != TRUE) { Swap_ShowMenuOptions(); gTasks[taskId].tState = STATE_MENU_HANDLE_INPUT; } break; case STATE_MENU_HANDLE_INPUT: if (sFactorySwapScreen->monPicAnimating != TRUE) { if (JOY_NEW(A_BUTTON)) { PlaySE(SE_SELECT); Swap_RunMenuOptionFunc(taskId); } else if (JOY_NEW(B_BUTTON)) { PlaySE(SE_SELECT); CloseMonPic(sFactorySwapScreen->monPic, &sFactorySwapScreen->monPicAnimating, TRUE); Swap_ErasePopupMenu(SWAP_WIN_OPTIONS); gTasks[taskId].tState = 0; gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_Task_HandleChooseMons) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_Task_HandleChooseMons); gTasks[taskId].tFollowUpTaskState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Swap_Task_ScreenInfoTransitionIn; } else if (JOY_REPEAT(DPAD_UP)) { Swap_UpdateMenuCursorPosition(-1); } else if (JOY_REPEAT(DPAD_DOWN)) { Swap_UpdateMenuCursorPosition(1); } } break; } } // Handles input on the two main swap screens (choosing a current pokeon to get rid of, and choosing a new pokemon to receive) static void Swap_Task_HandleChooseMons(u8 taskId) { switch (gTasks[taskId].tState) { case STATE_CHOOSE_MONS_INIT: if (!gPaletteFade.active) { sFactorySwapScreen->fadeSpeciesNameActive = TRUE; gTasks[taskId].tState = STATE_CHOOSE_MONS_HANDLE_INPUT; } break; case STATE_CHOOSE_MONS_HANDLE_INPUT: if (JOY_NEW(A_BUTTON)) { // Run whatever action is currently selected (a pokeball, the Cancel button, etc.) PlaySE(SE_SELECT); sFactorySwapScreen->fadeSpeciesNameActive = FALSE; Swap_PrintMonSpeciesAtFade(); Swap_EraseSpeciesWindow(); Swap_RunActionFunc(taskId); } else if (JOY_NEW(B_BUTTON)) { // Ask if player wants to quit swapping PlaySE(SE_SELECT); sFactorySwapScreen->fadeSpeciesNameActive = FALSE; Swap_PrintMonSpeciesAtFade(); Swap_EraseSpeciesWindow(); gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_AskQuitSwapping) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_AskQuitSwapping); gTasks[taskId].tState = 0; gTasks[taskId].tFollowUpTaskState = 0; gTasks[taskId].func = Swap_Task_ScreenInfoTransitionOut; } else if (JOY_REPEAT(DPAD_LEFT)) { Swap_UpdateBallCursorPosition(-1); Swap_PrintMonCategory(); Swap_PrintMonSpecies(); } else if (JOY_REPEAT(DPAD_RIGHT)) { Swap_UpdateBallCursorPosition(1); Swap_PrintMonCategory(); Swap_PrintMonSpecies(); } else if (JOY_REPEAT(DPAD_DOWN)) { Swap_UpdateActionCursorPosition(1); Swap_PrintMonCategory(); Swap_PrintMonSpecies(); } else if (JOY_REPEAT(DPAD_UP)) { Swap_UpdateActionCursorPosition(-1); Swap_PrintMonCategory(); Swap_PrintMonSpecies(); } break; } } static void Swap_Task_FadeSpeciesName(u8 taskId) { switch (gTasks[taskId].tState) { case FADESTATE_INIT: sFactorySwapScreen->fadeSpeciesNameCoeffDelay = 0; sFactorySwapScreen->fadeSpeciesNameCoeff = 0; sFactorySwapScreen->fadeSpeciesNameFadeOut = TRUE; gTasks[taskId].tState = FADESTATE_RUN; break; case FADESTATE_RUN: if (sFactorySwapScreen->fadeSpeciesNameActive) { if (sFactorySwapScreen->faceSpeciesNameDelay) { gTasks[taskId].tState = FADESTATE_DELAY; } else { sFactorySwapScreen->fadeSpeciesNameCoeffDelay++; if (sFactorySwapScreen->fadeSpeciesNameCoeffDelay > 6) { sFactorySwapScreen->fadeSpeciesNameCoeffDelay = 0; if (!sFactorySwapScreen->fadeSpeciesNameFadeOut) sFactorySwapScreen->fadeSpeciesNameCoeff--; else sFactorySwapScreen->fadeSpeciesNameCoeff++; } BlendPalettes(0x4000, sFactorySwapScreen->fadeSpeciesNameCoeff, 0); if (sFactorySwapScreen->fadeSpeciesNameCoeff > 5) { sFactorySwapScreen->fadeSpeciesNameFadeOut = FALSE; } else if (sFactorySwapScreen->fadeSpeciesNameCoeff == 0) { gTasks[taskId].tState = FADESTATE_DELAY; sFactorySwapScreen->fadeSpeciesNameFadeOut = TRUE; } } } break; case FADESTATE_DELAY: if (sFactorySwapScreen->faceSpeciesNameDelay > 14) { sFactorySwapScreen->faceSpeciesNameDelay = 0; gTasks[taskId].tState = FADESTATE_RUN; } else { sFactorySwapScreen->faceSpeciesNameDelay++; } break; } } #define tFadeOutFinished data[4] static void Swap_Task_FadeOutSpeciesName(u8 taskId) { switch (gTasks[taskId].tState) { case 0: sFactorySwapScreen->fadeSpeciesNameCoeffDelay = 0; gTasks[taskId].tFadeOutFinished = FALSE; gTasks[taskId].tState++; break; case 1: LoadPalette(&gPlttBufferUnfaded[0xF0], 0xE0, 0xA); gTasks[taskId].tState++; break; case 2: if (sFactorySwapScreen->fadeSpeciesNameCoeff > 15) { gTasks[taskId].tFadeOutFinished = TRUE; gTasks[taskId].tState++; } sFactorySwapScreen->fadeSpeciesNameCoeffDelay++; if (sFactorySwapScreen->fadeSpeciesNameCoeffDelay > 3) { sFactorySwapScreen->fadeSpeciesNameCoeffDelay = 0; gPlttBufferUnfaded[244] = gPlttBufferFaded[228]; sFactorySwapScreen->fadeSpeciesNameCoeff++; } BlendPalettes(0x4000, sFactorySwapScreen->fadeSpeciesNameCoeff, 0); break; } } // Slide current pokeballs offscreen to the right and new pokeballs onscreen from // the left during transition between player's/enemy's party screens #define tBallCycled(i) data[(i) + 1] static void Swap_Task_SlideCycleBalls(u8 taskId) { s8 i; u8 lastX; bool8 finished; switch (gTasks[taskId].tState) { case 0: gTasks[taskId].tBallCycled(0) = FALSE; gTasks[taskId].tBallCycled(1) = FALSE; gTasks[taskId].tBallCycled(2) = FALSE; gTasks[taskId].tState = 1; break; case 1: lastX = 0; for (i = FRONTIER_PARTY_SIZE - 1; i >= 0; i--) { if (i != FRONTIER_PARTY_SIZE - 1) { u8 posX = lastX - gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x; if (posX == 16 || gTasks[taskId].tBallCycled(i + 1) == TRUE) { lastX = gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x; gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x += 10; } else if (posX > 16) { gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x = gSprites[sFactorySwapScreen->ballSpriteIds[i + 1]].pos1.x - 48; } } else { lastX = gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x; gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x += 10; } if (gTasks[taskId].tBallCycled(i) == TRUE) { // New ball coming in from left, check if it has reached dest if (gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x > (i * 48) + 72) { // Overshot dest, set x and finish gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x = (i * 48) + 72; finished = TRUE; } else if (gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x == (i * 48) + 72) { finished = TRUE; } else { finished = FALSE; } } else { finished = FALSE; } if (gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x - 16 > DISPLAY_WIDTH) { // Ball is offscreen right, cycle its palette and move to left side of screen lastX = gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x; gSprites[sFactorySwapScreen->ballSpriteIds[i]].pos1.x = -16; if (sFactorySwapScreen->inEnemyScreen == TRUE) gSprites[sFactorySwapScreen->ballSpriteIds[i]].oam.paletteNum = IndexOfSpritePaletteTag(PALTAG_BALL_SELECTED); else gSprites[sFactorySwapScreen->ballSpriteIds[i]].oam.paletteNum = IndexOfSpritePaletteTag(PALTAG_BALL_GRAY); gTasks[taskId].tBallCycled(i) = TRUE; } } if (finished == TRUE) DestroyTask(taskId); break; } } // For sliding the action buttons (Cancel, Pkmn for Swap) on/off screen #define SLIDE_BUTTON_PKMN 0 #define SLIDE_BUTTON_CANCEL 1 #define tTaskId data[1] #define tSlidingOn data[2] #define tXIncrement data[3] // Data to be used by the task that creates this task #define tSecondSlideDelay data[2] #define tSlideFinishedPkmn data[3] #define tSlideFinishedCancel data[4] static void Swap_Task_SlideButtonOnOffScreen(u8 taskId) { u8 i, j; s32 posX = 0; s8 deltaX = gTasks[taskId].tXIncrement; bool8 sliding; s16 currPosX; u8 prevTaskId; if (gTasks[taskId].tSlidingOn == TRUE) deltaX *= -1; switch (gTasks[taskId].tState) { case SLIDE_BUTTON_PKMN: currPosX = gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0][0]].pos1.x; if (!gTasks[taskId].tSlidingOn) { // Sliding "Pkmn for Swap" offscreen if (currPosX + deltaX < DISPLAY_WIDTH) { sliding = TRUE; } else { sliding = FALSE; posX = DISPLAY_WIDTH; } } else { // Sliding "Pkmn for Swap" onscreen if (currPosX + deltaX > 160) { sliding = TRUE; } else { sliding = FALSE; posX = 160; } } if (sliding == TRUE) { // Do movement for (i = 0; i < ARRAY_COUNT(sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0]); i++) { for (j = 0; j < ARRAY_COUNT(sFactorySwapScreen->pkmnForSwapButtonSpriteIds); j++) gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[j][i]].pos1.x += deltaX; } } else { // Set final position for (j = 0; j < ARRAY_COUNT(sFactorySwapScreen->pkmnForSwapButtonSpriteIds); j++) { gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[j][0]].pos1.x = posX; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[j][1]].pos1.x = posX + 16; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[j][2]].pos1.x = posX + 48; } prevTaskId = gTasks[taskId].tTaskId; gTasks[prevTaskId].tSlideFinishedPkmn = TRUE; DestroyTask(taskId); } break; case SLIDE_BUTTON_CANCEL: currPosX = gSprites[sFactorySwapScreen->cancelButtonSpriteIds[0][0]].pos1.x; if (!gTasks[taskId].tSlidingOn) { // Sliding "Cancel" offscreen if (currPosX + deltaX < DISPLAY_WIDTH) { sliding = TRUE; } else { sliding = FALSE; posX = DISPLAY_WIDTH; } } else { // Sliding "Cancel" onscreen if (currPosX + deltaX > 192) { sliding = TRUE; } else { sliding = FALSE; posX = 192; } } if (sliding == TRUE) { // Do movement for (i = 0; i < ARRAY_COUNT(sFactorySwapScreen->cancelButtonSpriteIds); i++) { for (j = 0; j < ARRAY_COUNT(sFactorySwapScreen->cancelButtonSpriteIds[0]); j++) gSprites[sFactorySwapScreen->cancelButtonSpriteIds[j][i]].pos1.x += deltaX; } } else { // Set final position for (j = 0; j < ARRAY_COUNT(sFactorySwapScreen->cancelButtonSpriteIds); j++) { gSprites[sFactorySwapScreen->cancelButtonSpriteIds[j][0]].pos1.x = posX; gSprites[sFactorySwapScreen->cancelButtonSpriteIds[j][1]].pos1.x = posX + 16; } prevTaskId = gTasks[taskId].tTaskId; gTasks[prevTaskId].tSlideFinishedCancel = TRUE; DestroyTask(taskId); } break; } } // Slide action buttons offscreen static void Swap_Task_ScreenInfoTransitionOut(u8 taskId) { u8 slideTaskId; u16 hiPtr, loPtr; switch (gTasks[taskId].tState) { case 0: LoadPalette(sSwapText_Pal, 0xE0, sizeof(sSwapText_Pal)); Swap_PrintActionStrings(); PutWindowTilemap(SWAP_WIN_ACTION_FADE); gTasks[taskId].tState++; break; case 1: Swap_ErasePopupMenu(SWAP_WIN_OPTIONS); gTasks[taskId].tState++; break; case 2: BeginNormalPaletteFade(0x4000, 0, 0, 16, sPokeballGray_Pal[37]); gTasks[taskId].tState++; break; case 3: if (!gPaletteFade.active) { FillWindowPixelBuffer(SWAP_WIN_ACTION_FADE, PIXEL_FILL(0)); CopyWindowToVram(SWAP_WIN_ACTION_FADE, 2); if (sFactorySwapScreen->inEnemyScreen == TRUE) { // Start "Pkmn for Swap" button slide offscreen slideTaskId = CreateTask(Swap_Task_SlideButtonOnOffScreen, 0); gTasks[taskId].tSlideFinishedPkmn = FALSE; gTasks[slideTaskId].tTaskId = taskId; gTasks[slideTaskId].tState = SLIDE_BUTTON_PKMN; gTasks[slideTaskId].tSlidingOn = FALSE; gTasks[slideTaskId].tXIncrement = 6; gTasks[taskId].tSecondSlideDelay = 5; gTasks[taskId].tState++; } else { // Start "Cancel" button slide offscreen slideTaskId = CreateTask(Swap_Task_SlideButtonOnOffScreen, 0); gTasks[taskId].tSlideFinishedPkmn = TRUE; gTasks[taskId].tSlideFinishedCancel = FALSE; gTasks[slideTaskId].tTaskId = taskId; gTasks[slideTaskId].tState = SLIDE_BUTTON_CANCEL; gTasks[slideTaskId].tSlidingOn = FALSE; gTasks[slideTaskId].tXIncrement = 6; gTasks[taskId].tState += 2; } } break; case 4: // Start "Cancel" button slide offscreen for screens with both buttons if (gTasks[taskId].tSecondSlideDelay == 0) { slideTaskId = CreateTask(Swap_Task_SlideButtonOnOffScreen, 0); gTasks[taskId].tSlideFinishedCancel = FALSE; gTasks[slideTaskId].tTaskId = taskId; gTasks[slideTaskId].tState = SLIDE_BUTTON_CANCEL; gTasks[slideTaskId].tSlidingOn = FALSE; gTasks[slideTaskId].tXIncrement = 6; gTasks[taskId].tState++; } else { gTasks[taskId].tSecondSlideDelay--; } break; case 5: if (gTasks[taskId].tSlideFinishedPkmn == TRUE && gTasks[taskId].tSlideFinishedCancel == TRUE) { gTasks[taskId].tState = gTasks[taskId].tFollowUpTaskState; hiPtr = gTasks[taskId].tFollowUpTaskPtrHi; loPtr = gTasks[taskId].tFollowUpTaskPtrLo; gTasks[taskId].func = (void *)((hiPtr << 16) | (loPtr)); } break; } } // Slide action buttons onscreen, reprint swap dialogue and mon info static void Swap_Task_ScreenInfoTransitionIn(u8 taskId) { u8 slideTaskId; u16 hiPtr, loPtr; if (sFactorySwapScreen->monPicAnimating == TRUE) return; switch (gTasks[taskId].tState) { case 0: if (sFactorySwapScreen->inEnemyScreen == TRUE) { // Start "Pkmn for Swap" button slide onscreen slideTaskId = CreateTask(Swap_Task_SlideButtonOnOffScreen, 0); gTasks[taskId].tSlideFinishedPkmn = FALSE; gTasks[slideTaskId].tTaskId = taskId; gTasks[slideTaskId].tState = SLIDE_BUTTON_PKMN; gTasks[slideTaskId].tSlidingOn = TRUE; gTasks[slideTaskId].tXIncrement = 6; gTasks[taskId].tSecondSlideDelay = 10; gTasks[taskId].tState++; } else { // Start "Cancel" button slide onscreen slideTaskId = CreateTask(Swap_Task_SlideButtonOnOffScreen, 0); gTasks[taskId].tSlideFinishedPkmn = TRUE; gTasks[taskId].tSlideFinishedCancel = FALSE; gTasks[slideTaskId].tTaskId = taskId; gTasks[slideTaskId].tState = SLIDE_BUTTON_CANCEL; gTasks[slideTaskId].tSlidingOn = TRUE; gTasks[slideTaskId].tXIncrement = 6; gTasks[taskId].tState += 2; } break; case 1: // Start "Cancel" button slide onscreen for screens with both buttons if (gTasks[taskId].tSecondSlideDelay == 0) { slideTaskId = CreateTask(Swap_Task_SlideButtonOnOffScreen, 0); gTasks[taskId].tSlideFinishedCancel = FALSE; gTasks[slideTaskId].tTaskId = taskId; gTasks[slideTaskId].tState = SLIDE_BUTTON_CANCEL; gTasks[slideTaskId].tSlidingOn = TRUE; gTasks[slideTaskId].tXIncrement = 6; gTasks[taskId].tState++; } else { gTasks[taskId].tSecondSlideDelay--; } break; case 2: if (gTasks[taskId].tSlideFinishedPkmn == TRUE && gTasks[taskId].tSlideFinishedCancel == TRUE) { gPlttBufferFaded[226] = sPokeballGray_Pal[37]; Swap_PrintActionStrings(); PutWindowTilemap(SWAP_WIN_ACTION_FADE); gTasks[taskId].tState++; } break; case 3: BeginNormalPaletteFade(0x4000, 0, 16, 0, sPokeballGray_Pal[37]); gTasks[taskId].tState++; break; case 4: if (!gPaletteFade.active) { Swap_PrintOneActionString(0); gTasks[taskId].tState++; } break; case 5: Swap_PrintOneActionString(1); PutWindowTilemap(SWAP_WIN_OPTIONS); gTasks[taskId].tState++; break; case 6: FillWindowPixelBuffer(SWAP_WIN_ACTION_FADE, PIXEL_FILL(0)); CopyWindowToVram(SWAP_WIN_ACTION_FADE, 2); gTasks[taskId].tState++; break; case 7: if (!sFactorySwapScreen->inEnemyScreen) Swap_PrintOnInfoWindow(gText_SelectPkmnToSwap); else Swap_PrintOnInfoWindow(gText_SelectPkmnToAccept); if (sFactorySwapScreen->cursorPos < FRONTIER_PARTY_SIZE) gSprites[sFactorySwapScreen->cursorSpriteId].invisible = FALSE; Swap_PrintMonCategory(); gTasks[taskId].tState++; break; case 8: Swap_PrintMonSpeciesForTransition(); Swap_EraseSpeciesAtFadeWindow(); sFactorySwapScreen->fadeSpeciesNameActive = TRUE; gTasks[taskId].tState = gTasks[taskId].tFollowUpTaskState; hiPtr = gTasks[taskId].tFollowUpTaskPtrHi; loPtr = gTasks[taskId].tFollowUpTaskPtrLo; gTasks[taskId].func = (void *)((hiPtr << 16) | (loPtr)); break; } } #undef tTaskId #undef tSlidingOn #undef tXIncrement #undef tSlideFinishedPkmn #undef tSlideFinishedCancel // For switching between the swap screens with the player's / enemy's parties static void Swap_Task_SwitchPartyScreen(u8 taskId) { u8 i; if (sFactorySwapScreen->monPicAnimating == TRUE) return; switch (gTasks[taskId].tState) { case 0: Swap_PrintMonSpeciesForTransition(); gTasks[taskId].tState++; break; case 1: Swap_EraseSpeciesAtFadeWindow(); gSprites[sFactorySwapScreen->cursorSpriteId].invisible = TRUE; gTasks[taskId].tState++; break; case 2: CreateTask(Swap_Task_SlideCycleBalls, 0); gTasks[sFactorySwapScreen->fadeSpeciesNameTaskId].func = Swap_Task_FadeOutSpeciesName; gTasks[taskId].tState++; break; case 3: if (!FuncIsActiveTask(Swap_Task_SlideCycleBalls) && gTasks[sFactorySwapScreen->fadeSpeciesNameTaskId].tFadeOutFinished == TRUE) { Swap_EraseSpeciesWindow(); if (!sFactorySwapScreen->inEnemyScreen) { Swap_InitActions(SWAP_ENEMY_SCREEN); } else { Swap_InitActions(SWAP_PLAYER_SCREEN); // Hide "Pkmn for Swap" button for (i = 0; i < ARRAY_COUNT(sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0]); i++) gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[1][i]].invisible = TRUE; } gSprites[sFactorySwapScreen->cursorSpriteId].pos1.x = gSprites[sFactorySwapScreen->ballSpriteIds[sFactorySwapScreen->cursorPos]].pos1.x; gTasks[sFactorySwapScreen->fadeSpeciesNameTaskId].func = Swap_Task_FadeSpeciesName; sFactorySwapScreen->fadeSpeciesNameCoeffDelay = 0; sFactorySwapScreen->fadeSpeciesNameCoeff = 6; sFactorySwapScreen->fadeSpeciesNameFadeOut = FALSE; gTasks[sFactorySwapScreen->fadeSpeciesNameTaskId].tState = FADESTATE_RUN; gTasks[taskId].tState++; } break; case 4: gTasks[taskId].tState = 0; gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_Task_HandleChooseMons) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_Task_HandleChooseMons); gTasks[taskId].tFollowUpTaskState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Swap_Task_ScreenInfoTransitionIn; break; } } #undef tFadeOutFinished static void Swap_InitStruct(void) { if (sFactorySwapScreen == NULL) { sFactorySwapScreen = AllocZeroed(sizeof(*sFactorySwapScreen)); sFactorySwapScreen->cursorPos = 0; sFactorySwapScreen->monPicAnimating = FALSE; sFactorySwapScreen->fromSummaryScreen = FALSE; } } void DoBattleFactorySwapScreen(void) { sFactorySwapScreen = NULL; SetMainCallback2(CB2_InitSwapScreen); } static void CB2_InitSwapScreen(void) { u8 taskId; switch (gMain.state) { case 0: SetHBlankCallback(NULL); SetVBlankCallback(NULL); CpuFill32(0, (void *)VRAM, VRAM_SIZE); ResetBgsAndClearDma3BusyFlags(0); InitBgsFromTemplates(0, sSwap_BgTemplates, ARRAY_COUNT(sSwap_BgTemplates)); InitWindows(sSwap_WindowTemplates); DeactivateAllTextPrinters(); gMain.state++; break; case 1: sSwapMenuTilesetBuffer = Alloc(0x440); sSwapMonPicBgTilesetBuffer = AllocZeroed(0x440); sSwapMenuTilemapBuffer = Alloc(BG_SCREEN_SIZE); sSwapMonPicBgTilemapBuffer = AllocZeroed(BG_SCREEN_SIZE); ChangeBgX(0, 0, 0); ChangeBgY(0, 0, 0); ChangeBgX(1, 0, 0); ChangeBgY(1, 0, 0); ChangeBgX(2, 0, 0); ChangeBgY(2, 0, 0); ChangeBgX(3, 0, 0); ChangeBgY(3, 0, 0); SetGpuReg(REG_OFFSET_BLDY, 0); SetGpuReg(REG_OFFSET_MOSAIC, 0); SetGpuReg(REG_OFFSET_WIN0H, 0); SetGpuReg(REG_OFFSET_WIN0V, 0); SetGpuReg(REG_OFFSET_WIN1H, 0); SetGpuReg(REG_OFFSET_WIN1V, 0); SetGpuReg(REG_OFFSET_WININ, 0); SetGpuReg(REG_OFFSET_WINOUT, 0); gMain.state++; break; case 2: ResetPaletteFade(); ResetSpriteData(); ResetTasks(); FreeAllSpritePalettes(); ResetAllPicSprites(); CpuCopy16(gFrontierFactorySelectMenu_Gfx, sSwapMenuTilesetBuffer, 0x440); CpuCopy16(sMonPicBg_Gfx, sSwapMonPicBgTilesetBuffer, 0x60); LoadBgTiles(1, sSwapMenuTilesetBuffer, 0x440, 0); LoadBgTiles(3, sSwapMonPicBgTilesetBuffer, 0x60, 0); CpuCopy16(gFrontierFactorySelectMenu_Tilemap, sSwapMenuTilemapBuffer, BG_SCREEN_SIZE); LoadBgTilemap(1, sSwapMenuTilemapBuffer, BG_SCREEN_SIZE, 0); LoadPalette(gFrontierFactorySelectMenu_Pal, 0, 0x40); LoadPalette(sSwapText_Pal, 0xF0, sizeof(sSwapText_Pal)); LoadPalette(sSwapText_Pal, 0xE0, sizeof(sSwapText_Pal)); LoadPalette(sMonPicBg_Pal, 0x20, 4); gMain.state++; break; case 3: SetBgTilemapBuffer(3, sSwapMonPicBgTilemapBuffer); CopyToBgTilemapBufferRect(3, sMonPicBg_Tilemap, 11, 4, 8, 8); CopyBgTilemapBufferToVram(3); gMain.state++; break; case 4: LoadSpritePalettes(sSwap_SpritePalettes); LoadSpriteSheets(sSwap_SpriteSheets); LoadCompressedSpriteSheet(sSwap_BallGfx); SetVBlankCallback(Swap_VblankCb); gMain.state++; break; case 5: #ifdef UBFIX if (sFactorySwapScreen && sFactorySwapScreen->fromSummaryScreen) #else if (sFactorySwapScreen->fromSummaryScreen == TRUE) #endif sFactorySwapScreen->cursorPos = gLastViewedMonIndex; gMain.state++; break; case 6: Swap_InitStruct(); Swap_InitAllSprites(); if (sFactorySwapScreen->fromSummaryScreen == TRUE) Swap_ShowSummaryMonSprite(); Swap_InitActions(SWAP_PLAYER_SCREEN); gMain.state++; break; case 7: Swap_PrintOnInfoWindow(gText_SelectPkmnToSwap); PutWindowTilemap(SWAP_WIN_INFO); gMain.state++; break; case 8: Swap_PrintMonCategory(); PutWindowTilemap(SWAP_WIN_MON_CATEGORY); gMain.state++; break; case 9: if (!sFactorySwapScreen->fromSummaryScreen) Swap_PrintMonSpecies(); PutWindowTilemap(SWAP_WIN_SPECIES); gMain.state++; break; case 10: Swap_PrintPkmnSwap(); PutWindowTilemap(SWAP_WIN_TITLE); gMain.state++; break; case 11: gMain.state++; break; case 12: if (sFactorySwapScreen->fromSummaryScreen) Swap_PrintMonSpeciesAtFade(); gMain.state++; break; case 13: Swap_PrintActionStrings2(); PutWindowTilemap(SWAP_WIN_OPTIONS); gMain.state++; break; case 14: BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); ShowBg(0); ShowBg(1); ShowBg(2); if (sFactorySwapScreen->fromSummaryScreen == TRUE) { ShowBg(3); SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG3 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_OBJ); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(11, 4)); } else { HideBg(3); } gMain.state++; break; case 15: sFactorySwapScreen->fadeSpeciesNameTaskId = CreateTask(Swap_Task_FadeSpeciesName, 0); if (!sFactorySwapScreen->fromSummaryScreen) { gTasks[sFactorySwapScreen->fadeSpeciesNameTaskId].tState = FADESTATE_INIT; taskId = CreateTask(Swap_Task_HandleChooseMons, 0); gTasks[taskId].tState = STATE_CHOOSE_MONS_INIT; } else { Swap_EraseActionFadeWindow(); gTasks[sFactorySwapScreen->fadeSpeciesNameTaskId].tState = FADESTATE_RUN; sFactorySwapScreen->fadeSpeciesNameActive = FALSE; taskId = CreateTask(Swap_Task_HandleMenu, 0); gTasks[taskId].tState = STATE_MENU_INIT; } SetMainCallback2(Swap_CB2); break; } } static void Swap_InitAllSprites(void) { u8 i; u8 x; struct SpriteTemplate spriteTemplate; spriteTemplate = sSpriteTemplate_Swap_Pokeball; spriteTemplate.paletteTag = PALTAG_BALL_SELECTED; for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { sFactorySwapScreen->ballSpriteIds[i] = CreateSprite(&spriteTemplate, (48 * i) + 72, 64, 1); gSprites[sFactorySwapScreen->ballSpriteIds[i]].data[0] = 0; } sFactorySwapScreen->cursorSpriteId = CreateSprite(&sSpriteTemplate_Swap_Arrow, gSprites[sFactorySwapScreen->ballSpriteIds[sFactorySwapScreen->cursorPos]].pos1.x, 88, 0); sFactorySwapScreen->menuCursor1SpriteId = CreateSprite(&sSpriteTemplate_Swap_MenuHighlightLeft, 176, 112, 0); sFactorySwapScreen->menuCursor2SpriteId = CreateSprite(&sSpriteTemplate_Swap_MenuHighlightRight, 176, 144, 0); gSprites[sFactorySwapScreen->menuCursor1SpriteId].invisible = TRUE; gSprites[sFactorySwapScreen->menuCursor2SpriteId].invisible = TRUE; gSprites[sFactorySwapScreen->menuCursor1SpriteId].centerToCornerVecX = 0; gSprites[sFactorySwapScreen->menuCursor1SpriteId].centerToCornerVecY = 0; gSprites[sFactorySwapScreen->menuCursor2SpriteId].centerToCornerVecX = 0; gSprites[sFactorySwapScreen->menuCursor2SpriteId].centerToCornerVecY = 0; if (sFactorySwapScreen->fromSummaryScreen == TRUE) x = DISPLAY_WIDTH; else x = DISPLAY_WIDTH - 48; // Unusual way to create sprites // The sprite template for the selector arrow is re-used // with the tiles swapped out spriteTemplate = sSpriteTemplate_Swap_Arrow; spriteTemplate.tileTag = GFXTAG_ACTION_BOX_LEFT; sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0][0] = CreateSprite(&spriteTemplate, DISPLAY_WIDTH, 120, 10); spriteTemplate = sSpriteTemplate_Swap_MenuHighlightLeft; spriteTemplate.tileTag = GFXTAG_ACTION_BOX_RIGHT; sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0][1] = CreateSprite(&spriteTemplate, DISPLAY_WIDTH + 16, 120, 10); sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0][2] = CreateSprite(&spriteTemplate, DISPLAY_WIDTH + 48, 120, 10); spriteTemplate = sSpriteTemplate_Swap_Arrow; spriteTemplate.tileTag = GFXTAG_ACTION_HIGHLIGHT_LEFT; sFactorySwapScreen->pkmnForSwapButtonSpriteIds[1][0] = CreateSprite(&spriteTemplate, DISPLAY_WIDTH, 120, 1); spriteTemplate = sSpriteTemplate_Swap_MenuHighlightLeft; spriteTemplate.tileTag = GFXTAG_ACTION_HIGHLIGHT_MIDDLE; sFactorySwapScreen->pkmnForSwapButtonSpriteIds[1][1] = CreateSprite(&spriteTemplate, DISPLAY_WIDTH + 16, 120, 1); spriteTemplate.tileTag = GFXTAG_ACTION_HIGHLIGHT_RIGHT; sFactorySwapScreen->pkmnForSwapButtonSpriteIds[1][2] = CreateSprite(&spriteTemplate, DISPLAY_WIDTH + 48, 120, 1); spriteTemplate = sSpriteTemplate_Swap_Arrow; spriteTemplate.tileTag = GFXTAG_ACTION_BOX_LEFT; sFactorySwapScreen->cancelButtonSpriteIds[0][0] = CreateSprite(&spriteTemplate, x, 144, 10); spriteTemplate = sSpriteTemplate_Swap_MenuHighlightLeft; spriteTemplate.tileTag = GFXTAG_ACTION_BOX_RIGHT; sFactorySwapScreen->cancelButtonSpriteIds[0][1] = CreateSprite(&spriteTemplate, x + 16, 144, 10); spriteTemplate = sSpriteTemplate_Swap_Arrow; spriteTemplate.tileTag = GFXTAG_ACTION_HIGHLIGHT_LEFT; sFactorySwapScreen->cancelButtonSpriteIds[1][0] = CreateSprite(&spriteTemplate, x, 144, 1); spriteTemplate = sSpriteTemplate_Swap_MenuHighlightLeft; spriteTemplate.tileTag = GFXTAG_ACTION_HIGHLIGHT_RIGHT; sFactorySwapScreen->cancelButtonSpriteIds[1][1] = CreateSprite(&spriteTemplate, x + 16, 144, 1); for (i = 0; i < 2; i++) { gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][0]].centerToCornerVecX = 0; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][0]].centerToCornerVecY = 0; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][1]].centerToCornerVecX = 0; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][1]].centerToCornerVecY = 0; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][2]].centerToCornerVecX = 0; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][2]].centerToCornerVecY = 0; gSprites[sFactorySwapScreen->cancelButtonSpriteIds[i][0]].centerToCornerVecX = 0; gSprites[sFactorySwapScreen->cancelButtonSpriteIds[i][0]].centerToCornerVecY = 0; gSprites[sFactorySwapScreen->cancelButtonSpriteIds[i][1]].centerToCornerVecX = 0; gSprites[sFactorySwapScreen->cancelButtonSpriteIds[i][1]].centerToCornerVecY = 0; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][0]].invisible = TRUE; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][1]].invisible = TRUE; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][2]].invisible = TRUE; gSprites[sFactorySwapScreen->cancelButtonSpriteIds[i][0]].invisible = TRUE; gSprites[sFactorySwapScreen->cancelButtonSpriteIds[i][1]].invisible = TRUE; } gSprites[sFactorySwapScreen->cancelButtonSpriteIds[0][0]].invisible = FALSE; gSprites[sFactorySwapScreen->cancelButtonSpriteIds[0][1]].invisible = FALSE; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0][0]].invisible = FALSE; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0][1]].invisible = FALSE; gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0][2]].invisible = FALSE; } static void Swap_DestroyAllSprites(void) { u8 i, j; for (i = 0; i < FRONTIER_PARTY_SIZE; i++) DestroySprite(&gSprites[sFactorySwapScreen->ballSpriteIds[i]]); DestroySprite(&gSprites[sFactorySwapScreen->cursorSpriteId]); DestroySprite(&gSprites[sFactorySwapScreen->menuCursor1SpriteId]); DestroySprite(&gSprites[sFactorySwapScreen->menuCursor2SpriteId]); for (i = 0; i < ARRAY_COUNT(sFactorySwapScreen->pkmnForSwapButtonSpriteIds); i++) { for (j = 0; j < ARRAY_COUNT(sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0]); j++) DestroySprite(&gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[i][j]]); } for (i = 0; i < ARRAY_COUNT(sFactorySwapScreen->cancelButtonSpriteIds); i++) { for (j = 0; j < ARRAY_COUNT(sFactorySwapScreen->cancelButtonSpriteIds[0]); j++) DestroySprite(&gSprites[sFactorySwapScreen->cancelButtonSpriteIds[i][j]]); } } static void Swap_HandleActionCursorChange(u8 cursorId) { if (cursorId < FRONTIER_PARTY_SIZE) { // Cursor is on one of the pokemon gSprites[sFactorySwapScreen->cursorSpriteId].invisible = FALSE; Swap_HideActionButtonHighlights(); gSprites[sFactorySwapScreen->cursorSpriteId].pos1.x = gSprites[sFactorySwapScreen->ballSpriteIds[cursorId]].pos1.x; } else { // Cursor is on an action button gSprites[sFactorySwapScreen->cursorSpriteId].invisible = TRUE; Swap_HighlightActionButton(sFactorySwapScreen->actionsData[cursorId].id); } } static void Swap_UpdateBallCursorPosition(s8 direction) { u8 cursorPos; PlaySE(SE_SELECT); if (direction > 0) // Move cursor right. { if (sFactorySwapScreen->cursorPos + 1 != sFactorySwapScreen->actionsCount) sFactorySwapScreen->cursorPos++; else sFactorySwapScreen->cursorPos = 0; } else // Move cursor left. { if (sFactorySwapScreen->cursorPos != 0) sFactorySwapScreen->cursorPos--; else sFactorySwapScreen->cursorPos = sFactorySwapScreen->actionsCount - 1; } cursorPos = sFactorySwapScreen->cursorPos; Swap_HandleActionCursorChange(cursorPos); } static void Swap_UpdateActionCursorPosition(s8 direction) { u8 cursorPos; PlaySE(SE_SELECT); if (direction > 0) // Move cursor down. { if (sFactorySwapScreen->cursorPos < FRONTIER_PARTY_SIZE) sFactorySwapScreen->cursorPos = FRONTIER_PARTY_SIZE; else if (sFactorySwapScreen->cursorPos + 1 != sFactorySwapScreen->actionsCount) sFactorySwapScreen->cursorPos++; else sFactorySwapScreen->cursorPos = 0; } else // Move cursor up. { if (sFactorySwapScreen->cursorPos < FRONTIER_PARTY_SIZE) sFactorySwapScreen->cursorPos = sFactorySwapScreen->actionsCount - 1; else if (sFactorySwapScreen->cursorPos != 0) sFactorySwapScreen->cursorPos--; else sFactorySwapScreen->cursorPos = sFactorySwapScreen->actionsCount - 1; } cursorPos = sFactorySwapScreen->cursorPos; Swap_HandleActionCursorChange(cursorPos); } static void Swap_UpdateYesNoCursorPosition(s8 direction) { if (direction > 0) // Move cursor down. { if (sFactorySwapScreen->yesNoCursorPos != 1) sFactorySwapScreen->yesNoCursorPos++; else sFactorySwapScreen->yesNoCursorPos = 0; } else // Move cursor up. { if (sFactorySwapScreen->yesNoCursorPos != 0) sFactorySwapScreen->yesNoCursorPos--; else sFactorySwapScreen->yesNoCursorPos = 1; } gSprites[sFactorySwapScreen->menuCursor1SpriteId].pos1.y = (sFactorySwapScreen->yesNoCursorPos * 16) + 112; gSprites[sFactorySwapScreen->menuCursor2SpriteId].pos1.y = (sFactorySwapScreen->yesNoCursorPos * 16) + 112; } static void Swap_UpdateMenuCursorPosition(s8 direction) { PlaySE(SE_SELECT); if (direction > 0) // Move cursor down. { if (sFactorySwapScreen->menuCursorPos != ARRAY_COUNT(sSwap_MenuOptionFuncs) - 1) sFactorySwapScreen->menuCursorPos++; else sFactorySwapScreen->menuCursorPos = 0; } else // Move cursor up. { if (sFactorySwapScreen->menuCursorPos != 0) sFactorySwapScreen->menuCursorPos--; else sFactorySwapScreen->menuCursorPos = ARRAY_COUNT(sSwap_MenuOptionFuncs) - 1; } gSprites[sFactorySwapScreen->menuCursor1SpriteId].pos1.y = (sFactorySwapScreen->menuCursorPos * 16) + 112; gSprites[sFactorySwapScreen->menuCursor2SpriteId].pos1.y = (sFactorySwapScreen->menuCursorPos * 16) + 112; } static void Swap_HighlightActionButton(u8 actionId) { u8 i; for (i = 0; i < ARRAY_COUNT(sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0]); i++) { if (actionId == SWAPACTION_PKMN_FOR_SWAP) { // Show button highlight on "Pkmn for Swap" gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[1][i]].invisible = FALSE; // Hide button highlight on Cancel if (i < ARRAY_COUNT(sFactorySwapScreen->cancelButtonSpriteIds[0])) gSprites[sFactorySwapScreen->cancelButtonSpriteIds[1][i]].invisible = TRUE; } else if (actionId == SWAPACTION_CANCEL) { // Show button highlight on Cancel if (i < ARRAY_COUNT(sFactorySwapScreen->cancelButtonSpriteIds[0])) gSprites[sFactorySwapScreen->cancelButtonSpriteIds[1][i]].invisible = FALSE; // Hide button highlight on "Pkmn for Swap" gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[1][i]].invisible = TRUE; } } } static void Swap_HideActionButtonHighlights(void) { u8 i; for (i = 0; i < ARRAY_COUNT(sFactorySwapScreen->pkmnForSwapButtonSpriteIds[0]); i++) { // Hide button highlight on "Pkmn for Swap" gSprites[sFactorySwapScreen->pkmnForSwapButtonSpriteIds[1][i]].invisible = TRUE; // Hide button highlight on Cancel if (i < ARRAY_COUNT(sFactorySwapScreen->cancelButtonSpriteIds[0])) gSprites[sFactorySwapScreen->cancelButtonSpriteIds[1][i]].invisible = TRUE; } } static void Swap_ShowMenuOptions(void) { if (sFactorySwapScreen->fromSummaryScreen == TRUE) sFactorySwapScreen->fromSummaryScreen = FALSE; else sFactorySwapScreen->menuCursorPos = 0; gSprites[sFactorySwapScreen->menuCursor1SpriteId].pos1.x = 176; gSprites[sFactorySwapScreen->menuCursor1SpriteId].pos1.y = (sFactorySwapScreen->menuCursorPos * 16) + 112; gSprites[sFactorySwapScreen->menuCursor2SpriteId].pos1.x = 208; gSprites[sFactorySwapScreen->menuCursor2SpriteId].pos1.y = (sFactorySwapScreen->menuCursorPos * 16) + 112; gSprites[sFactorySwapScreen->menuCursor1SpriteId].invisible = FALSE; gSprites[sFactorySwapScreen->menuCursor2SpriteId].invisible = FALSE; Swap_PrintMenuOptions(); } static void Swap_ShowYesNoOptions(void) { sFactorySwapScreen->yesNoCursorPos = 0; gSprites[sFactorySwapScreen->menuCursor1SpriteId].pos1.x = 176; gSprites[sFactorySwapScreen->menuCursor1SpriteId].pos1.y = 112; gSprites[sFactorySwapScreen->menuCursor2SpriteId].pos1.x = 208; gSprites[sFactorySwapScreen->menuCursor2SpriteId].pos1.y = 112; gSprites[sFactorySwapScreen->menuCursor1SpriteId].invisible = FALSE; gSprites[sFactorySwapScreen->menuCursor2SpriteId].invisible = FALSE; Swap_PrintYesNoOptions(); } static void Swap_ErasePopupMenu(u8 windowId) { gSprites[sFactorySwapScreen->menuCursor1SpriteId].invisible = TRUE; gSprites[sFactorySwapScreen->menuCursor2SpriteId].invisible = TRUE; FillWindowPixelBuffer(windowId, PIXEL_FILL(0)); CopyWindowToVram(windowId, 2); ClearWindowTilemap(windowId); } static void Swap_EraseSpeciesWindow(void) { PutWindowTilemap(SWAP_WIN_SPECIES); FillWindowPixelBuffer(SWAP_WIN_SPECIES, PIXEL_FILL(0)); CopyWindowToVram(SWAP_WIN_SPECIES, 2); } static void Swap_EraseSpeciesAtFadeWindow(void) { PutWindowTilemap(SWAP_WIN_SPECIES_AT_FADE); FillWindowPixelBuffer(SWAP_WIN_SPECIES_AT_FADE, PIXEL_FILL(0)); CopyWindowToVram(SWAP_WIN_SPECIES_AT_FADE, 2); } static void Swap_EraseActionFadeWindow(void) { Swap_EraseSpeciesWindow(); PutWindowTilemap(SWAP_WIN_ACTION_FADE); FillWindowPixelBuffer(SWAP_WIN_ACTION_FADE, PIXEL_FILL(0)); CopyWindowToVram(SWAP_WIN_ACTION_FADE, 2); } static void Swap_PrintPkmnSwap(void) { FillWindowPixelBuffer(SWAP_WIN_TITLE, PIXEL_FILL(1)); AddTextPrinterParameterized(SWAP_WIN_TITLE, 1, gText_PkmnSwap, 2, 1, 0, NULL); CopyWindowToVram(SWAP_WIN_TITLE, 3); } static void Swap_PrintMonSpecies(void) { u16 species; u8 x; FillWindowPixelBuffer(SWAP_WIN_SPECIES, PIXEL_FILL(0)); if (sFactorySwapScreen->cursorPos >= FRONTIER_PARTY_SIZE) { CopyWindowToVram(SWAP_WIN_SPECIES, 2); } else { u8 monId = sFactorySwapScreen->cursorPos; if (!sFactorySwapScreen->inEnemyScreen) species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, NULL); else species = GetMonData(&gEnemyParty[monId], MON_DATA_SPECIES, NULL); StringCopy(gStringVar4, gSpeciesNames[species]); x = GetStringRightAlignXOffset(1, gStringVar4, 86); AddTextPrinterParameterized3(SWAP_WIN_SPECIES, 1, x, 1, sSwapSpeciesNameTextColors, 0, gStringVar4); CopyWindowToVram(SWAP_WIN_SPECIES, 3); } } static void Swap_PrintOnInfoWindow(const u8 *str) { FillWindowPixelBuffer(SWAP_WIN_INFO, PIXEL_FILL(0)); AddTextPrinterParameterized(SWAP_WIN_INFO, 1, str, 2, 5, 0, NULL); CopyWindowToVram(SWAP_WIN_INFO, 2); } static void Swap_PrintMenuOptions(void) { PutWindowTilemap(SWAP_WIN_OPTIONS); FillWindowPixelBuffer(SWAP_WIN_OPTIONS, PIXEL_FILL(0)); AddTextPrinterParameterized3(SWAP_WIN_OPTIONS, 1, 15, 1, sSwapMenuOptionsTextColors, 0, gText_Summary2); AddTextPrinterParameterized3(SWAP_WIN_OPTIONS, 1, 15, 17, sSwapMenuOptionsTextColors, 0, gText_Swap); AddTextPrinterParameterized3(SWAP_WIN_OPTIONS, 1, 15, 33, sSwapMenuOptionsTextColors, 0, gText_Rechoose); CopyWindowToVram(SWAP_WIN_OPTIONS, 3); } static void Swap_PrintYesNoOptions(void) { PutWindowTilemap(SWAP_WIN_YES_NO); FillWindowPixelBuffer(SWAP_WIN_YES_NO, PIXEL_FILL(0)); AddTextPrinterParameterized3(SWAP_WIN_YES_NO, 1, 7, 1, sSwapMenuOptionsTextColors, 0, gText_Yes3); AddTextPrinterParameterized3(SWAP_WIN_YES_NO, 1, 7, 17, sSwapMenuOptionsTextColors, 0, gText_No3); CopyWindowToVram(SWAP_WIN_YES_NO, 3); } static void Swap_PrintActionString(const u8 *str, u32 y, u32 windowId) { s32 x = GetStringRightAlignXOffset(0, str, 0x46); AddTextPrinterParameterized3(windowId, 0, x, y, sSwapMenuOptionsTextColors, 0, str); } static void Swap_PrintActionStrings(void) { FillWindowPixelBuffer(SWAP_WIN_ACTION_FADE, PIXEL_FILL(0)); switch (sFactorySwapScreen->inEnemyScreen) { case TRUE: Swap_PrintActionString(gText_PkmnForSwap, 0, SWAP_WIN_ACTION_FADE); case FALSE: Swap_PrintActionString(gText_Cancel3, 24, SWAP_WIN_ACTION_FADE); break; } CopyWindowToVram(SWAP_WIN_ACTION_FADE, 3); } static void Swap_PrintActionStrings2(void) { FillWindowPixelBuffer(SWAP_WIN_OPTIONS, PIXEL_FILL(0)); switch (sFactorySwapScreen->inEnemyScreen) { case TRUE: Swap_PrintActionString(gText_PkmnForSwap, 8, SWAP_WIN_OPTIONS); case FALSE: Swap_PrintActionString(gText_Cancel3, 32, SWAP_WIN_OPTIONS); break; } CopyWindowToVram(SWAP_WIN_OPTIONS, 3); } static void Swap_PrintOneActionString(u8 which) { switch (which) { case 0: if (sFactorySwapScreen->inEnemyScreen == TRUE) Swap_PrintActionString(gText_PkmnForSwap, 8, SWAP_WIN_OPTIONS); break; case 1: Swap_PrintActionString(gText_Cancel3, 32, SWAP_WIN_OPTIONS); break; } CopyWindowToVram(SWAP_WIN_OPTIONS, 3); } // For printing the species name once its selected. Keep the current fade but don't keep fading in and out static void Swap_PrintMonSpeciesAtFade(void) { u16 species; u8 x; u16 pal[5]; CpuCopy16(sSwapText_Pal, pal, 8); if (!sFactorySwapScreen->fromSummaryScreen) pal[4] = gPlttBufferFaded[228]; else pal[4] = sFactorySwapScreen->speciesNameColorBackup; LoadPalette(pal, 0xF0, sizeof(sSwapText_Pal)); PutWindowTilemap(SWAP_WIN_SPECIES_AT_FADE); FillWindowPixelBuffer(SWAP_WIN_SPECIES_AT_FADE, PIXEL_FILL(0)); if (sFactorySwapScreen->cursorPos >= FRONTIER_PARTY_SIZE) { CopyWindowToVram(SWAP_WIN_SPECIES_AT_FADE, 3); } else { u8 monId = sFactorySwapScreen->cursorPos; if (!sFactorySwapScreen->inEnemyScreen) species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, NULL); else species = GetMonData(&gEnemyParty[monId], MON_DATA_SPECIES, NULL); StringCopy(gStringVar4, gSpeciesNames[species]); x = GetStringRightAlignXOffset(1, gStringVar4, 86); AddTextPrinterParameterized3(SWAP_WIN_SPECIES_AT_FADE, 1, x, 1, sSwapSpeciesNameTextColors, 0, gStringVar4); CopyWindowToVram(SWAP_WIN_SPECIES_AT_FADE, 3); } } // Reprints the species name over the faded one after a transition static void Swap_PrintMonSpeciesForTransition(void) { u16 species; u8 x; LoadPalette(sSwapText_Pal, 0xE0, sizeof(sSwapText_Pal)); CpuCopy16(&gPlttBufferUnfaded[240], &gPlttBufferFaded[224], 10); if (sFactorySwapScreen->cursorPos >= FRONTIER_PARTY_SIZE) { CopyWindowToVram(SWAP_WIN_SPECIES, 2); } else { u8 monId = sFactorySwapScreen->cursorPos; if (!sFactorySwapScreen->inEnemyScreen) species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, NULL); else species = GetMonData(&gEnemyParty[monId], MON_DATA_SPECIES, NULL); StringCopy(gStringVar4, gSpeciesNames[species]); x = GetStringRightAlignXOffset(1, gStringVar4, 86); AddTextPrinterParameterized3(SWAP_WIN_SPECIES, 1, x, 1, sSwapSpeciesNameTextColors, 0, gStringVar4); CopyWindowToVram(SWAP_WIN_SPECIES, 3); } } static void Swap_PrintMonCategory(void) { u16 species; u8 text[30]; u8 x; u8 monId = sFactorySwapScreen->cursorPos; FillWindowPixelBuffer(SWAP_WIN_MON_CATEGORY, PIXEL_FILL(0)); if (monId >= FRONTIER_PARTY_SIZE) { CopyWindowToVram(SWAP_WIN_MON_CATEGORY, 2); } else { PutWindowTilemap(SWAP_WIN_MON_CATEGORY); if (!sFactorySwapScreen->inEnemyScreen) species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, NULL); else species = GetMonData(&gEnemyParty[monId], MON_DATA_SPECIES, NULL); CopyMonCategoryText(SpeciesToNationalPokedexNum(species), text); x = GetStringRightAlignXOffset(1, text, 0x76); AddTextPrinterParameterized(SWAP_WIN_MON_CATEGORY, 1, text, x, 1, 0, NULL); CopyWindowToVram(SWAP_WIN_MON_CATEGORY, 2); } } static void Swap_InitActions(u8 id) { if (sFactorySwapScreen->fromSummaryScreen != TRUE) { switch (id) { case SWAP_PLAYER_SCREEN: sFactorySwapScreen->inEnemyScreen = FALSE; sFactorySwapScreen->cursorPos = 0; sFactorySwapScreen->actionsCount = ARRAY_COUNT(sSwap_PlayerScreenActions); sFactorySwapScreen->actionsData = sSwap_PlayerScreenActions; break; case SWAP_ENEMY_SCREEN: sFactorySwapScreen->inEnemyScreen = TRUE; sFactorySwapScreen->cursorPos = 0; sFactorySwapScreen->actionsCount = ARRAY_COUNT(sSwap_EnemyScreenActions); sFactorySwapScreen->actionsData = sSwap_EnemyScreenActions; break; } } } static void Swap_RunMenuOptionFunc(u8 taskId) { sSwap_CurrentOptionFunc = sSwap_MenuOptionFuncs[sFactorySwapScreen->menuCursorPos]; sSwap_CurrentOptionFunc(taskId); } static void Swap_OptionSwap(u8 taskId) { CloseMonPic(sFactorySwapScreen->monPic, &sFactorySwapScreen->monPicAnimating, TRUE); sFactorySwapScreen->playerMonId = sFactorySwapScreen->cursorPos; Swap_ErasePopupMenu(SWAP_WIN_OPTIONS); gTasks[taskId].tState = 0; gTasks[taskId].func = Swap_Task_SwitchPartyScreen; } static void Swap_OptionSummary(u8 taskId) { gTasks[taskId].tState = STATE_SUMMARY_FADE; gTasks[taskId].func = Swap_Task_OpenSummaryScreen; } static void Swap_OptionRechoose(u8 taskId) { CloseMonPic(sFactorySwapScreen->monPic, &sFactorySwapScreen->monPicAnimating, TRUE); Swap_ErasePopupMenu(SWAP_WIN_OPTIONS); gTasks[taskId].tState = 0; gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_Task_HandleChooseMons) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_Task_HandleChooseMons); gTasks[taskId].tFollowUpTaskState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Swap_Task_ScreenInfoTransitionIn; } static void Swap_RunActionFunc(u8 taskId) { sSwap_CurrentOptionFunc = sFactorySwapScreen->actionsData[sFactorySwapScreen->cursorPos].func; sSwap_CurrentOptionFunc(taskId); } static void Swap_ActionCancel(u8 taskId) { gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_AskQuitSwapping) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_AskQuitSwapping); gTasks[taskId].tState = 0; gTasks[taskId].tFollowUpTaskState = 0; gTasks[taskId].func = Swap_Task_ScreenInfoTransitionOut; } static void Swap_ActionPkmnForSwap(u8 taskId) { gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_Task_SwitchPartyScreen) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_Task_SwitchPartyScreen); gTasks[taskId].tFollowUpTaskState = 0; gTasks[taskId].tState = 0; gTasks[taskId].func = Swap_Task_ScreenInfoTransitionOut; } static void Swap_ActionMon(u8 taskId) { if (!sFactorySwapScreen->inEnemyScreen) { gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_Task_HandleMenu) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_Task_HandleMenu); gTasks[taskId].tFollowUpTaskState = STATE_MENU_INIT; } else if (Swap_AlreadyHasSameSpecies(sFactorySwapScreen->cursorPos) == TRUE) { OpenMonPic(&sFactorySwapScreen->monPic.bgSpriteId, &sFactorySwapScreen->monPicAnimating, TRUE); gTasks[taskId].tState = 0; gTasks[taskId].tFollowUpTaskState = STATE_CHOOSE_MONS_HANDLE_INPUT; gTasks[taskId].func = Swap_TaskCantHaveSameMons; return; } else { gTasks[taskId].tFollowUpTaskPtrHi = (u32)(Swap_AskAcceptMon) >> 16; gTasks[taskId].tFollowUpTaskPtrLo = (u32)(Swap_AskAcceptMon); gTasks[taskId].tFollowUpTaskState = 0; } gTasks[taskId].tState = 0; gTasks[taskId].func = Swap_Task_ScreenInfoTransitionOut; } #define sIsSwapScreen data[7] static void OpenMonPic(u8 *spriteId, bool8 *animating, bool8 swapScreen) { *spriteId = CreateSprite(&sSpriteTemplate_Swap_MonPicBgAnim, 120, 64, 1); gSprites[*spriteId].callback = SpriteCB_OpenMonPic; gSprites[*spriteId].sIsSwapScreen = swapScreen; *animating = TRUE; } static void Swap_ShowSummaryMonSprite(void) { struct Pokemon *mon; u16 species; u32 personality, otId; sFactorySwapScreen->monPic.bgSpriteId = CreateSprite(&sSpriteTemplate_Swap_MonPicBgAnim, 120, 64, 1); StartSpriteAffineAnim(&gSprites[sFactorySwapScreen->monPic.bgSpriteId], 2); mon = &gPlayerParty[sFactorySwapScreen->cursorPos]; species = GetMonData(mon, MON_DATA_SPECIES, NULL); personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL); otId = GetMonData(mon, MON_DATA_OT_ID, NULL); #ifdef BUGFIX sFactorySwapScreen->monPic.monSpriteId = CreateMonPicSprite_HandleDeoxys(species, otId, personality, TRUE, 88, 32, 15, 0xFFFF); #else sFactorySwapScreen->monPic.monSpriteId = CreateMonPicSprite_HandleDeoxys(species, personality, otId, TRUE, 88, 32, 15, 0xFFFF); #endif gSprites[sFactorySwapScreen->monPic.monSpriteId].centerToCornerVecX = 0; gSprites[sFactorySwapScreen->monPic.monSpriteId].centerToCornerVecY = 0; gSprites[sFactorySwapScreen->monPic.bgSpriteId].invisible = TRUE; } static void CloseMonPic(struct FactoryMonPic pic, bool8 *animating, bool8 swapScreen) { u8 taskId; FreeAndDestroyMonPicSprite(pic.monSpriteId); taskId = CreateTask(Task_CloseMonPic, 1); gTasks[taskId].tIsSwapScreen = swapScreen; gTasks[taskId].tSpriteId = pic.bgSpriteId; gTasks[taskId].func(taskId); *animating = TRUE; } static void HideMonPic(struct FactoryMonPic pic, bool8 *animating) { FreeAndDestroyMonPicSprite(pic.monSpriteId); FreeOamMatrix(gSprites[pic.bgSpriteId].oam.matrixNum); DestroySprite(&gSprites[pic.bgSpriteId]); *animating = FALSE; } static void Swap_TaskCantHaveSameMons(u8 taskId) { if (sFactorySwapScreen->monPicAnimating == TRUE) return; switch (gTasks[taskId].tState) { case 0: Swap_PrintOnInfoWindow(gText_SamePkmnInPartyAlready); sFactorySwapScreen->monSwapped = FALSE; gTasks[taskId].tState++; break; case 1: if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON)) { PlaySE(SE_SELECT); CloseMonPic(sFactorySwapScreen->monPic, &sFactorySwapScreen->monPicAnimating, TRUE); gTasks[taskId].tState++; } break; case 2: if (sFactorySwapScreen->monPicAnimating != TRUE) { FillWindowPixelBuffer(SWAP_WIN_ACTION_FADE, PIXEL_FILL(0)); CopyWindowToVram(SWAP_WIN_ACTION_FADE, 2); gTasks[taskId].tState++; } break; case 3: Swap_PrintOnInfoWindow(gText_SelectPkmnToAccept); gTasks[taskId].tState++; break; case 4: Swap_PrintMonSpeciesForTransition(); Swap_EraseSpeciesAtFadeWindow(); sFactorySwapScreen->fadeSpeciesNameActive = TRUE; gTasks[taskId].tState = gTasks[taskId].tFollowUpTaskState; gTasks[taskId].func = Swap_Task_HandleChooseMons; break; } } static bool8 Swap_AlreadyHasSameSpecies(u8 monId) { u8 i; u16 species = GetMonData(&gEnemyParty[monId], MON_DATA_SPECIES, NULL); for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { if (i != sFactorySwapScreen->playerMonId && (u16)(GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL)) == species) return TRUE; } return FALSE; } static void SpriteCB_OpenMonPic(struct Sprite *sprite) { u8 taskId; if (sprite->affineAnimEnded) { sprite->invisible = TRUE; taskId = CreateTask(Task_OpenMonPic, 1); gTasks[taskId].tIsSwapScreen = sprite->sIsSwapScreen; gTasks[taskId].func(taskId); sprite->callback = SpriteCallbackDummy; } } static void SpriteCB_CloseMonPic(struct Sprite *sprite) { if (sprite->affineAnimEnded) { FreeOamMatrix(sprite->oam.matrixNum); if (sprite->sIsSwapScreen == TRUE) sFactorySwapScreen->monPicAnimating = FALSE; else Select_SetMonPicAnimating(FALSE); DestroySprite(sprite); } } static void Task_OpenMonPic(u8 taskId) { struct Task *task = &gTasks[taskId]; switch (task->tState) { case 0: // Init task->tWinLeft = 88; task->tWinRight = DISPLAY_WIDTH - 88; task->tWinTop = 64; task->tWinBottom = 65; SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(task->tWinLeft, task->tWinRight)); SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom)); SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ); SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG2 | WINOUT_WIN01_CLR | WINOUT_WIN01_OBJ); break; case 1: // Show mon pic bg ShowBg(3); SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG3 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_OBJ); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(11, 4)); break; case 2: // Animate mon pic bg task->tWinTop -= 4; task->tWinBottom += 4; if (task->tWinTop <= 32 || task->tWinBottom >= 96) { task->tWinTop = 32; task->tWinBottom = 96; } SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom)); if (task->tWinTop != 32) return; break; default: DestroyTask(taskId); // UB: Should not use the task after it has been deleted. if (gTasks[taskId].tIsSwapScreen == TRUE) Swap_CreateMonSprite(); else Select_CreateMonSprite(); return; } task->tState++; } static void Task_CloseMonPic(u8 taskId) { struct Task *task = &gTasks[taskId]; switch (task->tState) { case 0: // Init task->tWinLeft = 88; task->tWinRight = DISPLAY_WIDTH - 88; task->tWinTop = 32; task->tWinBottom = 96; SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(task->tWinLeft, task->tWinRight)); SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom)); SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ); SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG2 | WINOUT_WIN01_CLR | WINOUT_WIN01_OBJ); task->tState++; break; case 1: // Animate bg task->tWinTop += 4; task->tWinBottom -= 4; if (task->tWinTop >= 64 || task->tWinBottom <= 65) { task->tWinTop = 64; task->tWinBottom = 65; } SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom)); if (task->tWinTop == 64) task->tState++; break; default: // Hide bg HideBg(3); gSprites[task->tSpriteId].sIsSwapScreen = task->tIsSwapScreen; gSprites[task->tSpriteId].invisible = FALSE; gSprites[task->tSpriteId].callback = SpriteCB_CloseMonPic; StartSpriteAffineAnim(&gSprites[task->tSpriteId], 1); ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); DestroyTask(taskId); break; } } static void Swap_CreateMonSprite(void) { struct Pokemon *mon; u16 species; u32 personality, otId; if (!sFactorySwapScreen->inEnemyScreen) mon = &gPlayerParty[sFactorySwapScreen->cursorPos]; else mon = &gEnemyParty[sFactorySwapScreen->cursorPos]; species = GetMonData(mon, MON_DATA_SPECIES, NULL); personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL); otId = GetMonData(mon, MON_DATA_OT_ID, NULL); sFactorySwapScreen->monPic.monSpriteId = CreateMonPicSprite_HandleDeoxys(species, otId, personality, TRUE, 88, 32, 15, 0xFFFF); gSprites[sFactorySwapScreen->monPic.monSpriteId].centerToCornerVecX = 0; gSprites[sFactorySwapScreen->monPic.monSpriteId].centerToCornerVecY = 0; sFactorySwapScreen->monPicAnimating = FALSE; }