sovereignx/src/pokedex_plus_hgss.c

8606 lines
291 KiB
C

#include "global.h"
#include "battle_main.h"
#include "battle_util.h"
#include "bg.h"
#include "contest_effect.h"
#include "data.h"
#include "daycare.h"
#include "decompress.h"
#include "event_data.h"
#include "gpu_regs.h"
#include "graphics.h"
#include "international_string_util.h"
#include "item.h"
#include "item_icon.h"
#include "main.h"
#include "malloc.h"
#include "menu.h"
#include "m4a.h"
#include "overworld.h"
#include "palette.h"
#include "party_menu.h"
#include "pokedex.h"
#include "pokedex_plus_hgss.h"
#include "pokedex_area_screen.h"
#include "pokedex_cry_screen.h"
#include "pokemon_icon.h"
#include "pokemon_summary_screen.h"
#include "region_map.h"
#include "pokemon.h"
#include "reset_rtc_screen.h"
#include "scanline_effect.h"
#include "shop.h"
#include "sound.h"
#include "sprite.h"
#include "string_util.h"
#include "strings.h"
#include "task.h"
#include "text_window.h"
#include "trainer_pokemon_sprites.h"
#include "trig.h"
#include "window.h"
#include "constants/abilities.h"
#include "constants/form_change_types.h"
#include "constants/items.h"
#include "constants/moves.h"
#include "constants/party_menu.h"
#include "constants/rgb.h"
#include "constants/songs.h"
enum
{
PAGE_MAIN,
PAGE_INFO,
PAGE_SEARCH,
PAGE_SEARCH_RESULTS,
PAGE_UNK,
PAGE_AREA,
PAGE_CRY,
PAGE_SIZE
};
enum
{
INFO_SCREEN,
STATS_SCREEN,
EVO_SCREEN,
FORMS_SCREEN,
AREA_SCREEN,
CRY_SCREEN,
SIZE_SCREEN,
CANCEL_SCREEN,
SCREEN_COUNT
};
enum
{
SEARCH_NAME,
SEARCH_COLOR,
SEARCH_TYPE_LEFT,
SEARCH_TYPE_RIGHT,
SEARCH_ORDER,
SEARCH_MODE,
SEARCH_OK,
SEARCH_COUNT
};
enum
{
SEARCH_TOPBAR_SEARCH,
SEARCH_TOPBAR_SHIFT,
SEARCH_TOPBAR_CANCEL,
SEARCH_TOPBAR_COUNT
};
enum
{
ORDER_NUMERICAL,
ORDER_ALPHABETICAL,
ORDER_HEAVIEST,
ORDER_LIGHTEST,
ORDER_TALLEST,
ORDER_SMALLEST
};
enum
{
NAME_ABC = 1,
NAME_DEF,
NAME_GHI,
NAME_JKL,
NAME_MNO,
NAME_PQR,
NAME_STU,
NAME_VWX,
NAME_YZ,
};
extern const u16 gPokedexOrder_Alphabetical[];
extern const u16 gPokedexOrder_Height[];
extern const u16 gPokedexOrder_Weight[];
// static .rodata strings
static const u8 sText_No0000[] = _("0000");
static const u8 sCaughtBall_Gfx[] = INCBIN_U8("graphics/pokedex/caught_ball.4bpp");
static const u8 sText_TenDashes[] = _("----------");
ALIGNED(4) static const u8 sExpandedPlaceholder_PokedexDescription[] = _("");
static const u16 sSizeScreenSilhouette_Pal[] = INCBIN_U16("graphics/pokedex/size_silhouette.gbapal");
static const u8 sText_Stats_Buttons[] = _("{A_BUTTON}TOGGLE {DPAD_UPDOWN}MOVES");
static const u8 sText_Stats_Buttons_Decapped[] = _("{A_BUTTON}Toggle {DPAD_UPDOWN}Moves");
static const u8 sText_Stats_HP[] = _("HP");
static const u8 sText_Stats_Attack[] = _("ATK");
static const u8 sText_Stats_Defense[] = _("DEF");
static const u8 sText_Stats_Speed[] = _("SPE");
static const u8 sText_Stats_SpAttack[] = _("SP.A");
static const u8 sText_Stats_SpDefense[] = _("SP.D");
static const u8 sText_Stats_EV_Plus1[] = _("{UP_ARROW_2}");
static const u8 sText_Stats_EV_Plus2[] = _("{UP_ARROW_2}{UP_ARROW_2}");
static const u8 sText_Stats_EV_Plus3[] = _("{UP_ARROW_2}{UP_ARROW_2}{UP_ARROW_2}");
static const u8 sText_Stats_EvStr1Str2[] = _("{STR_VAR_1}{STR_VAR_2}");
static const u8 sText_Stats_MoveSelectedMax[] = _("{STR_VAR_1} / {STR_VAR_2}");
static const u8 sText_Stats_MoveLevel[] = _("LVL");
static const u8 sText_Stats_Gender_0[] = _("");
static const u8 sText_Stats_Gender_12_5[] = _("♀ 1/7 ♂"); //_("♀ 12.5 / 87.5 ♂");
static const u8 sText_Stats_Gender_25[] = _("♀ 1/3 ♂"); //_("♀ 25 / 75 ♂");
static const u8 sText_Stats_Gender_50[] = _("♀ 1/1 ♂"); //_("♀ 50 / 50 ♂");
static const u8 sText_Stats_Gender_75[] = _("♀ 3/1 ♂"); //_("♀ 75 / 25 ♂");
static const u8 sText_Stats_Gender_87_5[] = _("♀ 7/1 ♂");
static const u8 sText_Stats_Gender_100[] = _("");
static const u8 sText_Stats_CatchRate[] = _("CATCH{0x5B}: ");
static const u8 sText_Stats_CatchRate_Legend[] = _("LEGENDARY");
static const u8 sText_Stats_CatchRate_VeryHard[] = _("VERY HARD");
static const u8 sText_Stats_CatchRate_Difficult[] = _("DIFFICULT");
static const u8 sText_Stats_CatchRate_Medium[] = _("MEDIUM");
static const u8 sText_Stats_CatchRate_Relaxed[] = _("RELAXED");
static const u8 sText_Stats_CatchRate_Easy[] = _("EASY");
static const u8 sText_Stats_ExpYield[] = _("EXP YIELD: ");
static const u8 sText_Stats_EggCycles[] = _("HATCH STEPS:");
static const u8 sText_Stats_EggCycles_VeryFast[] = _("{EMOJI_BOLT}{EMOJI_DIZZYEGG}");
static const u8 sText_Stats_EggCycles_Fast[] = _("{EMOJI_DIZZYEGG}");
static const u8 sText_Stats_EggCycles_Normal[] = _("{EMOJI_DIZZYEGG}{EMOJI_DIZZYEGG}");
static const u8 sText_Stats_EggCycles_Slow[] = _("{EMOJI_DIZZYEGG}{EMOJI_DIZZYEGG}{EMOJI_DIZZYEGG}");
static const u8 sText_Stats_Growthrate[] = _("GROW: ");
static const u8 sText_Stats_Friendship[] = _("FRIENDSHIP:");
static const u8 sText_Stats_Friendship_BigAnger[] = _("{EMOJI_BIGANGER}");
static const u8 sText_Stats_Friendship_Neutral[] = _("{EMOJI_NEUTRAL}");
static const u8 sText_Stats_Friendship_Happy[] = _("{EMOJI_HAPPY}");
static const u8 sText_Stats_Friendship_BigSmile[] = _("{EMOJI_BIGSMILE}");
static const u8 sText_Stats_MEDIUM_FAST[] = _("MED. FAST");
static const u8 sText_Stats_ERRATIC[] = _("ERRATIC");
static const u8 sText_Stats_FLUCTUATING[] = _("FLUCTUATING");
static const u8 sText_Stats_MEDIUM_SLOW[] = _("MED. SLOW");
static const u8 sText_Stats_FAST[] = _("FAST");
static const u8 sText_Stats_SLOW[] = _("SLOW");
static const u8 sText_Stats_ContestHeart[] = _("H");
static const u8 sText_Stats_Minus[] = _("-");
static const u8 sText_Stats_eggGroup[] = _("EGG G1:");
static const u8 sText_Stats_eggGroup_Groups[] = _("{STR_VAR_1}/{STR_VAR_2}");
static const u8 sText_Stats_eggGroup_MONSTER[] = _("MONSTER");
static const u8 sText_Stats_eggGroup_WATER_1[] = _("WATER {CIRCLE_1}");
static const u8 sText_Stats_eggGroup_BUG[] = _("BUG");
static const u8 sText_Stats_eggGroup_FLYING[] = _("FLYING");
static const u8 sText_Stats_eggGroup_FIELD[] = _("FIELD");
static const u8 sText_Stats_eggGroup_FAIRY[] = _("FAIRY");
static const u8 sText_Stats_eggGroup_GRASS[] = _("GRASS");
static const u8 sText_Stats_eggGroup_HUMAN_LIKE[] = _("HUMANE");
static const u8 sText_Stats_eggGroup_WATER_3[] = _("WATER {CIRCLE_3}");
static const u8 sText_Stats_eggGroup_MINERAL[] = _("MINERAL");
static const u8 sText_Stats_eggGroup_AMORPHOUS[] = _("AMORPHOUS");
static const u8 sText_Stats_eggGroup_WATER_2[] = _("WATER {CIRCLE_2}");
static const u8 sText_Stats_eggGroup_DITTO[] = _("DITTO");
static const u8 sText_Stats_eggGroup_DRAGON[] = _("DRAGON");
static const u8 sText_Stats_eggGroup_NO_EGGS_DISCOVERED[] = _("---");
static const u8 sText_Stats_eggGroup_UNKNOWN[] = _("???");
static const u8 sText_Dex_SEEN[] = _("SEEN");
static const u8 sText_Dex_OWN[] = _("OWN");
static const u8 sText_EVO_Buttons[] = _("{DPAD_UPDOWN}EVOs {A_BUTTON}CHECK");
static const u8 sText_EVO_Buttons_Decapped[] = _("{DPAD_UPDOWN}Evos {A_BUTTON}Check");
static const u8 sText_EVO_Buttons_PE[] = _("{DPAD_UPDOWN}EVOs {A_BUTTON}CHECK {START_BUTTON}FORMs");
static const u8 sText_EVO_Buttons_Decapped_PE[] = _("{DPAD_UPDOWN}Evos {A_BUTTON}Check {START_BUTTON}Forms");
static const u8 sText_EVO_Name[] = _("{STR_VAR_3}:");
static const u8 sText_EVO_PreEvo[] = _("{STR_VAR_1} evolves from {STR_VAR_2}");
static const u8 sText_EVO_PreEvo_PE_Mega[] = _("{STR_VAR_1} Mega Evolves with {STR_VAR_2}");
static const u8 sText_EVO_FRIENDSHIP[] = _("{LV}{UP_ARROW}, high friendship");
static const u8 sText_EVO_FRIENDSHIP_DAY[] = _("{LV}{UP_ARROW}, high friendship, day");
static const u8 sText_EVO_FRIENDSHIP_NIGHT[] = _("{LV}{UP_ARROW}, high friendship, night");
static const u8 sText_EVO_FRIENDSHIP_MOVE_TYPE[] = _("{LV}{UP_ARROW}, high friendship, {STR_VAR_2} move");
static const u8 sText_EVO_LEVEL[] = _("{LV}{UP_ARROW} to {STR_VAR_2}");
static const u8 sText_EVO_TRADE[] = _("Trading");
static const u8 sText_EVO_TRADE_ITEM[] = _("Trading, holding {STR_VAR_2}");
static const u8 sText_EVO_ITEM[] = _("{STR_VAR_2} is used");
static const u8 sText_EVO_LEVEL_ATK_GT_DEF[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, Atk > Def");
static const u8 sText_EVO_LEVEL_ATK_EQ_DEF[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, Atk = Def");
static const u8 sText_EVO_LEVEL_ATK_LT_DEF[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, Atk < Def");
static const u8 sText_EVO_LEVEL_SILCOON[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, Silcoon persona");
static const u8 sText_EVO_LEVEL_CASCOON[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, Cascoon persona");
static const u8 sText_EVO_LEVEL_NINJASK[] = _("{LV}{UP_ARROW} to {STR_VAR_2}");
static const u8 sText_EVO_LEVEL_SHEDINJA[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, party<6, 1x POKéBALL");
static const u8 sText_EVO_BEAUTY[] = _("{LV}{UP_ARROW}, high beauty");
static const u8 sText_EVO_LEVEL_FEMALE[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, is female");
static const u8 sText_EVO_LEVEL_MALE[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, is male");
static const u8 sText_EVO_LEVEL_NIGHT[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, night");
static const u8 sText_EVO_LEVEL_DAY[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, day");
static const u8 sText_EVO_LEVEL_DUSK[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, dusk (5-6PM)");
static const u8 sText_EVO_ITEM_HOLD_DAY[] = _("{LV}{UP_ARROW}, holds {STR_VAR_2}, day");
static const u8 sText_EVO_ITEM_HOLD_NIGHT[] = _("{LV}{UP_ARROW}, holds {STR_VAR_2}, night");
static const u8 sText_EVO_MOVE[] = _("{LV}{UP_ARROW}, knows {STR_VAR_2}");
static const u8 sText_EVO_MAPSEC[] = _("{LV}{UP_ARROW} on {STR_VAR_2}");
static const u8 sText_EVO_ITEM_MALE[] = _("{STR_VAR_2} used on male");
static const u8 sText_EVO_ITEM_FEMALE[] = _("{STR_VAR_2} used on female");
static const u8 sText_EVO_LEVEL_RAIN[] = _("{LV}{UP_ARROW} to {STR_VAR_2} while raining");
static const u8 sText_EVO_SPECIFIC_MON_IN_PARTY[] = _("{LV}{UP_ARROW} with {STR_VAR_2} in party");
static const u8 sText_EVO_LEVEL_DARK_TYPE_MON_IN_PARTY[] = _("{LV}{UP_ARROW} with dark type in party");
static const u8 sText_EVO_TRADE_SPECIFIC_MON[] = _("Traded for {STR_VAR_2}");
static const u8 sText_EVO_SPECIFIC_MAP[] = _("{LV}{UP_ARROW} on {STR_VAR_2}");
static const u8 sText_EVO_LEVEL_NATURE_AMPED[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, Amped natures");
static const u8 sText_EVO_LEVEL_NATURE_LOW_KEY[] = _("{LV}{UP_ARROW} to {STR_VAR_2}, Low Key natures");
static const u8 sText_EVO_CRITICAL_HITS[] = _("Land {STR_VAR_2} critical hits in\nsingle battle");
static const u8 sText_EVO_SCRIPT_TRIGGER_DMG[] = _("Takes at least {STR_VAR_2} HP in damage");
static const u8 sText_EVO_DARK_SCROLL[] = _("ScrllOfDrknss is used");
static const u8 sText_EVO_WATER_SCROLL[] = _("ScrollOfWatrs is used");
static const u8 sText_EVO_ITEM_NIGHT[] = _("{STR_VAR_2} is used, night");
static const u8 sText_EVO_ITEM_DAY[] = _("{STR_VAR_2} is used, day");
static const u8 sText_EVO_ITEM_HOLD[] = _("{LV}{UP_ARROW}, holds {STR_VAR_2}");
static const u8 sText_EVO_USE_MOVE_TWENTY_TIMES[] = _("{LV}{UP_ARROW} after 20x {STR_VAR_2}");
static const u8 sText_EVO_RECOIL_DAMAGE_MALE[] = _("{LV}{UP_ARROW} with {STR_VAR_2} recoil, male");
static const u8 sText_EVO_RECOIL_DAMAGE_FEMALE[] = _("{LV}{UP_ARROW} with {STR_VAR_2} recoil, female");
static const u8 sText_EVO_ITEM_COUNT_999[] = _("{LV}{UP_ARROW} with 999 {STR_VAR_2} in bag");
static const u8 sText_EVO_DEFEAT_THREE_WITH_ITEM[] = _("{LV}{UP_ARROW} defeating 3 {STR_VAR_3} holding {STR_VAR_2}");
static const u8 sText_EVO_OVERWORLD_STEPS[] = _("{LV}{UP_ARROW} after {STR_VAR_2} steps");
static const u8 sText_EVO_UNKNOWN[] = _("Method unknown");
static const u8 sText_EVO_NONE[] = _("{STR_VAR_1} has no evolution.");
static const u8 sText_FORMS_Buttons_PE[] = _("{A_BUTTON}FORM MODE {START_BUTTON}EVOs");
static const u8 sText_FORMS_Buttons_Decapped_PE[] = _("{START_BUTTON}Evos");
static const u8 sText_FORMS_Buttons_Submenu_PE[] = _("{DPAD_NONE}FORMs {A_BUTTON}CHECK {START_BUTTON}EVOs");
static const u8 sText_FORMS_Buttons_Submenu_Decapped_PE[] = _("{START_BUTTON}Evos");
static const u8 sText_FORMS_NONE[] = _("{STR_VAR_1} has no alternate forms.");
static const u8 sText_PlusSymbol[] = _("+");
// static .rodata graphics
static const u16 sPokedexPlusHGSS_Default_Pal[] = INCBIN_U16("graphics/pokedex/hgss/palette_default.gbapal");
static const u16 sPokedexPlusHGSS_National_Pal[] = INCBIN_U16("graphics/pokedex/hgss/palette_national.gbapal");
static const u16 sPokedexPlusHGSS_MenuSearch_Pal[] = INCBIN_U16("graphics/pokedex/hgss/palette_search_menu.gbapal");
static const u16 sPokedexPlusHGSS_SearchResults_Pal[] = INCBIN_U16("graphics/pokedex/hgss/palette_search_results.gbapal");
static const u16 sPokedexPlusHGSS_Default_dark_Pal[] = INCBIN_U16("graphics/pokedex/hgss/palette_default_dark.gbapal");
static const u16 sPokedexPlusHGSS_National_dark_Pal[] = INCBIN_U16("graphics/pokedex/hgss/palette_national_dark.gbapal");
static const u16 sPokedexPlusHGSS_MenuSearch_dark_Pal[] = INCBIN_U16("graphics/pokedex/hgss/palette_search_menu_dark.gbapal");
static const u16 sPokedexPlusHGSS_SearchResults_dark_Pal[] = INCBIN_U16("graphics/pokedex/hgss/palette_search_results_dark.gbapal");
static const u32 sPokedexPlusHGSS_MenuList_Gfx[] = INCBIN_U32("graphics/pokedex/hgss/tileset_menu_list.4bpp.lz");
static const u32 sPokedexPlusHGSS_MenuList_DECA_Gfx[] = INCBIN_U32("graphics/pokedex/hgss/tileset_menu_list_DECA.4bpp.lz");
static const u32 sPokedexPlusHGSS_Interface_Gfx[] = INCBIN_U32("graphics/pokedex/hgss/tileset_interface.4bpp.lz");
static const u32 sPokedexPlusHGSS_Interface_DECA_Gfx[] = INCBIN_U32("graphics/pokedex/hgss/tileset_interface_DECA.4bpp.lz");
static const u32 sPokedexPlusHGSS_Menu_1_Gfx[] = INCBIN_U32("graphics/pokedex/hgss/tileset_menu1.4bpp.lz");
static const u32 sPokedexPlusHGSS_Menu_2_Gfx[] = INCBIN_U32("graphics/pokedex/hgss/tileset_menu2.4bpp.lz");
static const u32 sPokedexPlusHGSS_Menu_3_Gfx[] = INCBIN_U32("graphics/pokedex/hgss/tileset_menu3.4bpp.lz");
static const u32 sPokedexPlusHGSS_MenuSearch_Gfx[] = INCBIN_U32("graphics/pokedex/hgss/tileset_menu_search.4bpp.lz");
static const u32 sPokedexPlusHGSS_MenuSearch_DECA_Gfx[] = INCBIN_U32("graphics/pokedex/hgss/tileset_menu_search_DECA.4bpp.lz");
static const u32 sPokedexPlusHGSS_StartMenuMain_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_start_menu.bin.lz");
static const u32 sPokedexPlusHGSS_StartMenuSearchResults_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_start_menu_search_results.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenSelectBarSubmenu_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/SelectBar.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenSelectBarSubmenu_Tilemap_Clear[] = INCBIN_U32("graphics/pokedex/hgss/SelectBar_clear.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenList_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_list_screen.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenListUnderlay_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_list_screen_underlay.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenInfo_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_info_screen.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenStats_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_stats_screen.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenEvolution_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_evo_screen.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenEvolution_Tilemap_PE[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_evo_screen_PE.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenForms_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_forms_screen.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenCry_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_cry_screen.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenSize_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_size_screen.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenSearchHoenn_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_search_screen_hoenn.bin.lz");
static const u32 sPokedexPlusHGSS_ScreenSearchNational_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/tilemap_search_screen_national.bin.lz");
#define SCROLLING_MON_X 146
#define HGSS_DECAPPED FALSE
#define HGSS_DARK_MODE FALSE
#define HGSS_HIDE_UNSEEN_EVOLUTION_NAMES FALSE
// For scrolling search parameter
#define MAX_SEARCH_PARAM_ON_SCREEN 6
#define MAX_SEARCH_PARAM_CURSOR_POS (MAX_SEARCH_PARAM_ON_SCREEN - 1)
#define MAX_MONS_ON_SCREEN 4
#define MAX_EVOLUTION_ICONS 8
#define LIST_SCROLL_STEP 16
#define POKEBALL_ROTATION_TOP 64
#define POKEBALL_ROTATION_BOTTOM (POKEBALL_ROTATION_TOP - 16)
// Coordinates of the Pokémon sprite on its page (info/cry screens)
#define MON_PAGE_X 48
#define MON_PAGE_Y 56
static EWRAM_DATA struct PokedexView *sPokedexView = NULL;
static EWRAM_DATA u16 sLastSelectedPokemon = 0;
static EWRAM_DATA u8 sPokeBallRotation = 0;
static EWRAM_DATA struct PokedexListItem *sPokedexListItem = NULL;
//Pokedex Plus HGSS_Ui
#define MOVES_COUNT_TOTAL (EGG_MOVES_ARRAY_COUNT + MAX_LEVEL_UP_MOVES + NUM_TECHNICAL_MACHINES + NUM_HIDDEN_MACHINES)
EWRAM_DATA static u16 sStatsMoves[MOVES_COUNT_TOTAL] = {0};
EWRAM_DATA static u16 sStatsMovesTMHM_ID[NUM_TECHNICAL_MACHINES + NUM_HIDDEN_MACHINES] = {0};
struct SearchOptionText
{
const u8 *description;
const u8 *title;
};
struct SearchOption
{
const struct SearchOptionText *texts;
u8 taskDataCursorPos;
u8 taskDataScrollOffset;
u16 numOptions;
};
struct SearchMenuTopBarItem
{
const u8 *description;
u8 highlightX;
u8 highlightY;
u8 highlightWidth;
};
struct SearchMenuItem
{
const u8 *description;
u8 titleBgX;
u8 titleBgY;
u8 titleBgWidth;
u8 selectionBgX;
u8 selectionBgY;
u8 selectionBgWidth;
};
struct PokedexListItem
{
u16 dexNum;
u16 seen:1;
u16 owned:1;
};
struct PokemonStats
{
u16 species;
u8 genderRatio;
u8 baseHP;
u8 baseSpeed;
u8 baseAttack;
u8 baseSpAttack;
u8 baseDefense;
u8 baseSpDefense;
u8 differentEVs;
u8 evYield_HP;
u8 evYield_Speed;
u8 evYield_Attack;
u8 evYield_SpAttack;
u8 evYield_Defense;
u8 evYield_SpDefense;
u8 catchRate;
u8 growthRate;
u8 eggGroup1;
u8 eggGroup2;
u8 eggCycles;
u16 expYield;
u8 friendship;
u16 ability0;
u16 ability1;
u16 abilityHidden;
};
struct EvoScreenData
{
bool8 fromEvoPage;
u8 numAllEvolutions;
u16 targetSpecies[10];
u8 numSeen;
bool8 seen[10];
u8 menuPos;
u8 arrowSpriteId;
bool8 isMega;
};
struct FromScreenData
{
u8 numForms;
u16 formIds[30];
bool8 inSubmenu;
u8 menuPos;
u8 arrowSpriteId;
};
struct PokedexView
{
struct PokedexListItem pokedexList[NATIONAL_DEX_COUNT + 1];
u16 pokemonListCount;
u16 selectedPokemon;
u16 selectedPokemonBackup;
u16 dexMode;
u16 dexModeBackup;
u16 dexOrder;
u16 dexOrderBackup;
u16 seenCount;
u16 ownCount;
u16 monSpriteIds[MAX_MONS_ON_SCREEN];
u8 typeIconSpriteIds[2];
u16 moveSelected;
u8 movesTotal;
u8 statBarsSpriteId;
u8 statBarsBgSpriteId;
bool8 justScrolled;
u8 categoryIconSpriteId; //Physical/Special/Status category
u8 numEggMoves;
u8 numLevelUpMoves;
u8 numTMHMMoves;
u8 numTutorMoves;
u8 numPreEvolutions;
struct PokemonStats sPokemonStats;
struct EvoScreenData sEvoScreenData;
struct FromScreenData sFormScreenData;
u16 formSpecies;
u16 selectedMonSpriteId;
u16 pokeBallRotationStep;
u16 pokeBallRotationBackup;
u8 pokeBallRotation;
u8 initialVOffset;
u8 scrollTimer;
u8 scrollDirection;
s16 listVOffset;
s16 listMovingVOffset;
u16 scrollMonIncrement;
u16 maxScrollTimer;
u16 scrollSpeed;
u16 unkArr1[4]; // Cleared, never read
u16 originalSearchSelectionNum;
u8 filler[6];
u8 currentPage;
u8 currentPageBackup;
bool8 isSearchResults:1;
u8 selectedScreen;
u8 screenSwitchState;
u8 menuIsOpen;
u16 menuCursorPos;
s16 menuY; //Menu Y position (inverted because we use REG_BG0VOFS for this)
u8 unkArr2[8]; // Cleared, never read
u8 unkArr3[8]; // Cleared, never read
};
static void ResetPokedexView(struct PokedexView *pokedexView);
static void VBlankCB_Pokedex(void);
static void CB2_Pokedex(void);
static void Task_OpenPokedexMainPage(u8);
static void Task_HandlePokedexInput(u8);
static void Task_WaitForScroll(u8);
static void Task_HandlePokedexStartMenuInput(u8);
static void Task_OpenInfoScreenAfterMonMovement(u8);
static void Task_WaitForExitInfoScreen(u8);
static void Task_WaitForExitSearch(u8);
static void Task_ClosePokedex(u8);
static void Task_OpenSearchResults(u8);
static void Task_HandleSearchResultsInput(u8);
static void Task_WaitForSearchResultsScroll(u8);
static void Task_HandleSearchResultsStartMenuInput(u8);
static void Task_OpenSearchResultsInfoScreenAfterMonMovement(u8);
static void Task_WaitForExitSearchResultsInfoScreen(u8);
static void Task_ReturnToPokedexFromSearchResults(u8);
static void Task_ClosePokedexFromSearchResultsStartMenu(u8);
static bool8 LoadPokedexListPage(u8);
static void LoadPokedexBgPalette(bool8);
static void FreeWindowAndBgBuffers(void);
static void CreatePokedexList(u8, u8);
static void CreateMonDexNum(u16, u8, u8, u16);
static void CreateCaughtBall(u16, u8, u8, u16);
static u8 CreateMonName(u16, u8, u8);
static void ClearMonListEntry(u8 x, u8 y, u16 unused);
static void CreateMonSpritesAtPos(u16, u16);
static bool8 UpdateDexListScroll(u8, u8, u8);
static u16 TryDoPokedexScroll(u16, u16);
static void UpdateSelectedMonSpriteId(void);
static bool8 TryDoInfoScreenScroll(void);
static u8 ClearMonSprites(void);
static u16 GetPokemonSpriteToDisplay(u16);
static u32 CreatePokedexMonSprite(u16, s16, s16);
static void CreateInterfaceSprites(u8);
static void SpriteCB_MoveMonForInfoScreen(struct Sprite *sprite);
static void SpriteCB_Scrollbar(struct Sprite *sprite);
static void SpriteCB_ScrollArrow(struct Sprite *sprite);
static void SpriteCB_DexListInterfaceText(struct Sprite *sprite);
static void SpriteCB_RotatingPokeBall(struct Sprite *sprite);
static void SpriteCB_SeenOwnInfo(struct Sprite *sprite);
static void SpriteCB_DexListStartMenuCursor(struct Sprite *sprite);
static void SpriteCB_PokedexListMonSprite(struct Sprite *sprite);
static u8 LoadInfoScreen(struct PokedexListItem *, u8 monSpriteId);
static bool8 IsInfoScreenScrolling(u8);
static u8 StartInfoScreenScroll(struct PokedexListItem *, u8);
static void Task_LoadInfoScreen(u8);
static void Task_HandleInfoScreenInput(u8);
static void Task_SwitchScreensFromInfoScreen(u8);
static void Task_LoadInfoScreenWaitForFade(u8);
static void Task_ExitInfoScreen(u8);
static void Task_LoadAreaScreen(u8);
static void Task_WaitForAreaScreenInput(u8 taskId);
static void Task_SwitchScreensFromAreaScreen(u8);
static void Task_LoadCryScreen(u8);
static void Task_HandleCryScreenInput(u8);
static void Task_SwitchScreensFromCryScreen(u8);
static void LoadPlayArrowPalette(bool8);
static void Task_LoadSizeScreen(u8);
static void Task_HandleSizeScreenInput(u8);
static void Task_SwitchScreensFromSizeScreen(u8);
static void LoadScreenSelectBarMain(u16);
static void HighlightScreenSelectBarItem(u8, u16);
static void Task_HandleCaughtMonPageInput(u8);
static void Task_ExitCaughtMonPage(u8);
static void SpriteCB_SlideCaughtMonToCenter(struct Sprite *sprite);
static void PrintMonInfo(u32 num, u32, u32 owned, u32 newEntry);
static void ResetOtherVideoRegisters(u16);
static u8 PrintCryScreenSpeciesName(u8, u16, u8, u8);
static void PrintDecimalNum(u8 windowId, u16 num, u8 left, u8 top);
static u16 CreateMonSpriteFromNationalDexNumberHGSS(u16 nationalNum, s16 x, s16 y, u16 paletteSlot);
static u16 CreateSizeScreenTrainerPic(u16, s16, s16, s8);
static u16 GetNextPosition(u8, u16, u16, u16);
static u8 LoadSearchMenu(void);
static void Task_LoadSearchMenu(u8);
static void Task_SwitchToSearchMenuTopBar(u8);
static void Task_HandleSearchTopBarInput(u8);
static void Task_SwitchToSearchMenu(u8);
static void Task_HandleSearchMenuInput(u8);
static void Task_StartPokedexSearch(u8);
static void Task_WaitAndCompleteSearch(u8);
static void Task_SearchCompleteWaitForInput(u8);
static void Task_SelectSearchMenuItem(u8);
static void Task_HandleSearchParameterInput(u8);
static void Task_ExitSearch(u8);
static void Task_ExitSearchWaitForFade(u8);
static void HighlightSelectedSearchTopBarItem(u8);
static void HighlightSelectedSearchMenuItem(u8, u8);
static void PrintSelectedSearchParameters(u8);
static void DrawOrEraseSearchParameterBox(bool8);
static void PrintSearchParameterText(u8);
static u8 GetSearchModeSelection(u8 taskId, u8 option);
static void SetDefaultSearchModeAndOrder(u8);
static void CreateSearchParameterScrollArrows(u8);
static void EraseAndPrintSearchTextBox(const u8 *);
static void EraseSelectorArrow(u32);
static void PrintSelectorArrow(u32);
static void PrintSearchParameterTitle(u32, const u8 *);
static void ClearSearchParameterBoxText(void);
static void SetSpriteInvisibility(u8 spriteArrayId, bool8 invisible);
static void CreateTypeIconSprites(void);
static void SetSearchRectHighlight(u8 flags, u8 x, u8 y, u8 width);
static void PrintInfoSubMenuText(u8 windowId, const u8 *str, u8 left, u8 top);
//Stats screen HGSS_Ui
static void LoadTilesetTilemapHGSS(u8 page);
static void Task_HandleStatsScreenInput(u8 taskId);
static void Task_LoadStatsScreen(u8 taskId);
static void Task_SwitchScreensFromStatsScreen(u8 taskId);
static void Task_ExitStatsScreen(u8 taskId);
static bool8 CalculateMoves(void);
static void PrintStatsScreen_NameGender(u8 taskId, u32 num, u32 value);
static void PrintStatsScreen_DestroyMoveItemIcon(u8 taskId);
static void PrintStatsScreen_Moves_Top(u8 taskId);
static void PrintStatsScreen_Moves_Description(u8 taskId);
static void PrintStatsScreen_Moves_BottomText(u8 taskId);
static void PrintStatsScreen_Moves_Bottom(u8 taskId);
static void PrintStatsScreen_Left(u8 taskId);
static void PrintStatsScreen_Abilities(u8 taskId);
static void PrintInfoScreenTextWhite(const u8* str, u8 left, u8 top);
static void PrintInfoScreenTextSmall(const u8* str, u8 left, u8 top);
static void PrintInfoScreenTextSmallWhite(const u8* str, u8 left, u8 top);
static void Task_LoadEvolutionScreen(u8 taskId);
static void Task_HandleEvolutionScreenInput(u8 taskId);
static void Task_SwitchScreensFromEvolutionScreen(u8 taskId);
static void Task_ExitEvolutionScreen(u8 taskId);
static void PrintEvolutionTargetSpeciesAndMethod(u8 taskId, u16 species, u8 depth, u32 *depth_i, u32 alreadyPrintedIcons[], u32 *icon_depth_i);
static u8 PrintPreEvolutions(u8 taskId, u16 species);
//Stat bars on scrolling screens
static void TryDestroyStatBars(void);
static void TryDestroyStatBarsBg(void);
static void CreateStatBars(struct PokedexListItem *dexMon);
static void CreateStatBarsBg(void);
static void SpriteCB_StatBars(struct Sprite *sprite);
static void SpriteCB_StatBarsBg(struct Sprite *sprite);
//Forms screen
static void Task_LoadFormsScreen(u8 taskId);
static void Task_HandleFormsScreenInput(u8 taskId);
static void PrintForms(u8 taskId, u16 species);
static void Task_SwitchScreensFromFormsScreen(u8 taskId);
static void Task_ExitFormsScreen(u8 taskId);
//Physical/Special/Status category icon
static u8 ShowCategoryIcon(u32 category);
static void DestroyCategoryIcon(void);
static u16 NationalPokedexNumToSpeciesHGSS(u16 nationalNum);
//Stat bars by DizzyEgg
#define TAG_STAT_BAR 4097
#define TAG_STAT_BAR_BG 4098
static const struct OamData sOamData_StatBar =
{
.y = 160,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
.size = SPRITE_SIZE(64x64),
};
static const struct OamData sOamData_StatBarBg =
{
.y = 160,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
.size = SPRITE_SIZE(64x64),
};
static const struct SpriteTemplate sStatBarSpriteTemplate =
{
.tileTag = TAG_STAT_BAR,
.paletteTag = TAG_STAT_BAR,
.oam = &sOamData_StatBar,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_StatBars,
};
static const struct SpriteTemplate sStatBarBgSpriteTemplate =
{
.tileTag = TAG_STAT_BAR_BG,
.paletteTag = TAG_STAT_BAR_BG,
.oam = &sOamData_StatBarBg,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_StatBarsBg,
};
enum
{
COLOR_ID_ALPHA,
COLOR_ID_BAR_WHITE,
// These are repeated 6 times
COLOR_ID_FILL,
COLOR_ID_FILL_SHADOW,
COLOR_ID_FONT = 14,
COLOR_ID_FONT_SHADOW = 15,
};
enum
{
COLOR_BEST, // Light blue
COLOR_VERY_GOOD, // Green
COLOR_GOOD, // Light Green
COLOR_AVERAGE, // Yellow
COLOR_BAD, // Orange
COLOR_WORST, // Red
};
static const u8 sStatBarsGfx[] = INCBIN_U8("graphics/pokedex/hgss/stat_bars.4bpp");
static const u16 sStatBarPalette[16] = {
[COLOR_ID_ALPHA] = RGB(0, 0, 10),
[COLOR_ID_BAR_WHITE] = RGB_WHITE,
[COLOR_ID_FILL + COLOR_BEST * 2] = RGB(2, 25, 25),
[COLOR_ID_FILL_SHADOW + COLOR_BEST * 2] = RGB(13, 27, 27),
[COLOR_ID_FILL + COLOR_VERY_GOOD * 2] = RGB(11, 25, 2),
[COLOR_ID_FILL_SHADOW + COLOR_VERY_GOOD * 2] = RGB(19, 27, 13),
[COLOR_ID_FILL + COLOR_GOOD * 2] = RGB(22, 25, 2),
[COLOR_ID_FILL_SHADOW + COLOR_GOOD * 2] = RGB(26, 27, 13),
[COLOR_ID_FILL + COLOR_AVERAGE * 2] = RGB(25, 22, 2),
[COLOR_ID_FILL_SHADOW + COLOR_AVERAGE * 2] = RGB(27, 26, 13),
[COLOR_ID_FILL + COLOR_BAD * 2] = RGB(25, 17, 2),
[COLOR_ID_FILL_SHADOW + COLOR_BAD * 2] = RGB(27, 22, 13),
[COLOR_ID_FILL + COLOR_WORST * 2] = RGB(25, 4, 2),
[COLOR_ID_FILL_SHADOW + COLOR_WORST * 2] = RGB(27, 15, 13),
[COLOR_ID_FONT] = RGB_BLACK,
[COLOR_ID_FONT_SHADOW] = RGB(22, 22, 22),
};
static const struct SpritePalette sStatBarSpritePal[] = //{sStatBarPalette, TAG_STAT_BAR};
{
{sStatBarPalette, TAG_STAT_BAR},
{sStatBarPalette, TAG_STAT_BAR_BG},
{0}
};
static const struct OamData sOamData_ScrollBar =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(8x8),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(8x8),
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
.affineParam = 0
};
static const struct OamData sOamData_ScrollArrow =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(16x8),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(16x8),
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0
};
static const struct OamData sOamData_InterfaceText =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(32x16),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(32x16),
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0
};
static const struct OamData sOamData_RotatingPokeBall =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_WINDOW,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(32x32),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(32x32),
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
.affineParam = 0
};
static const struct OamData sOamData_SeenOwnText =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x32),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(64x32),
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0
};
static const struct OamData sOamData_Dex8x16 =
{
.y = DISPLAY_HEIGHT,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.mosaic = FALSE,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(8x16),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(8x16),
.tileNum = 0,
.priority = 0,
.paletteNum = 0,
.affineParam = 0
};
static const union AnimCmd sSpriteAnim_ScrollBar[] =
{
ANIMCMD_FRAME(3, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_ScrollArrow[] =
{
ANIMCMD_FRAME(1, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_RotatingPokeBall[] =
{
ANIMCMD_FRAME(16, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_StartButton[] =
{
ANIMCMD_FRAME(48, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_SearchText[] =
{
ANIMCMD_FRAME(40, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_SelectButton[] =
{
ANIMCMD_FRAME(32, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_MenuText[] =
{
ANIMCMD_FRAME(56, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_SeenText[] =
{
ANIMCMD_FRAME(64, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_OwnText[] =
{
ANIMCMD_FRAME(96, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennText[] =
{
ANIMCMD_FRAME(160, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalText[] =
{
ANIMCMD_FRAME(168, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit0[] =
{
ANIMCMD_FRAME(128, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit1[] =
{
ANIMCMD_FRAME(130, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit2[] =
{
ANIMCMD_FRAME(132, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit3[] =
{
ANIMCMD_FRAME(134, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit4[] =
{
ANIMCMD_FRAME(136, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit5[] =
{
ANIMCMD_FRAME(138, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit6[] =
{
ANIMCMD_FRAME(140, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit7[] =
{
ANIMCMD_FRAME(142, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit8[] =
{
ANIMCMD_FRAME(144, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_HoennSeenOwnDigit9[] =
{
ANIMCMD_FRAME(146, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit0[] =
{
ANIMCMD_FRAME(176, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit1[] =
{
ANIMCMD_FRAME(178, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit2[] =
{
ANIMCMD_FRAME(180, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit3[] =
{
ANIMCMD_FRAME(182, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit4[] =
{
ANIMCMD_FRAME(184, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit5[] =
{
ANIMCMD_FRAME(186, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit6[] =
{
ANIMCMD_FRAME(188, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit7[] =
{
ANIMCMD_FRAME(190, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit8[] =
{
ANIMCMD_FRAME(192, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_NationalSeenOwnDigit9[] =
{
ANIMCMD_FRAME(194, 30),
ANIMCMD_END
};
static const union AnimCmd sSpriteAnim_DexListStartMenuCursor[] =
{
ANIMCMD_FRAME(4, 30),
ANIMCMD_END
};
static const union AnimCmd *const sSpriteAnimTable_ScrollBar[] =
{
sSpriteAnim_ScrollBar
};
static const union AnimCmd *const sSpriteAnimTable_ScrollArrow[] =
{
sSpriteAnim_ScrollArrow
};
static const union AnimCmd *const sSpriteAnimTable_RotatingPokeBall[] =
{
sSpriteAnim_RotatingPokeBall
};
static const union AnimCmd *const sSpriteAnimTable_InterfaceText[] =
{
sSpriteAnim_StartButton,
sSpriteAnim_SearchText,
sSpriteAnim_SelectButton,
sSpriteAnim_MenuText
};
static const union AnimCmd *const sSpriteAnimTable_SeenOwnText[] =
{
sSpriteAnim_SeenText,
sSpriteAnim_OwnText
};
static const union AnimCmd *const sSpriteAnimTable_HoennNationalText[] =
{
sSpriteAnim_HoennText,
sSpriteAnim_NationalText
};
static const union AnimCmd *const sSpriteAnimTable_HoennSeenOwnNumber[] =
{
sSpriteAnim_HoennSeenOwnDigit0,
sSpriteAnim_HoennSeenOwnDigit1,
sSpriteAnim_HoennSeenOwnDigit2,
sSpriteAnim_HoennSeenOwnDigit3,
sSpriteAnim_HoennSeenOwnDigit4,
sSpriteAnim_HoennSeenOwnDigit5,
sSpriteAnim_HoennSeenOwnDigit6,
sSpriteAnim_HoennSeenOwnDigit7,
sSpriteAnim_HoennSeenOwnDigit8,
sSpriteAnim_HoennSeenOwnDigit9
};
static const union AnimCmd *const sSpriteAnimTable_NationalSeenOwnNumber[] =
{
sSpriteAnim_NationalSeenOwnDigit0,
sSpriteAnim_NationalSeenOwnDigit1,
sSpriteAnim_NationalSeenOwnDigit2,
sSpriteAnim_NationalSeenOwnDigit3,
sSpriteAnim_NationalSeenOwnDigit4,
sSpriteAnim_NationalSeenOwnDigit5,
sSpriteAnim_NationalSeenOwnDigit6,
sSpriteAnim_NationalSeenOwnDigit7,
sSpriteAnim_NationalSeenOwnDigit8,
sSpriteAnim_NationalSeenOwnDigit9
};
static const union AnimCmd *const sSpriteAnimTable_DexListStartMenuCursor[] =
{
sSpriteAnim_DexListStartMenuCursor
};
#define TAG_DEX_INTERFACE 4096 // Tile and pal tag used for all interface sprites.
static const struct SpriteTemplate sScrollBarSpriteTemplate =
{
.tileTag = TAG_DEX_INTERFACE,
.paletteTag = TAG_DEX_INTERFACE,
.oam = &sOamData_ScrollBar,
.anims = sSpriteAnimTable_ScrollBar,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_Scrollbar,
};
static const struct SpriteTemplate sScrollArrowSpriteTemplate =
{
.tileTag = TAG_DEX_INTERFACE,
.paletteTag = TAG_DEX_INTERFACE,
.oam = &sOamData_ScrollArrow,
.anims = sSpriteAnimTable_ScrollArrow,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_ScrollArrow,
};
static const struct SpriteTemplate sInterfaceTextSpriteTemplate =
{
.tileTag = TAG_DEX_INTERFACE,
.paletteTag = TAG_DEX_INTERFACE,
.oam = &sOamData_InterfaceText,
.anims = sSpriteAnimTable_InterfaceText,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_DexListInterfaceText,
};
static const struct SpriteTemplate sRotatingPokeBallSpriteTemplate =
{
.tileTag = TAG_DEX_INTERFACE,
.paletteTag = TAG_DEX_INTERFACE,
.oam = &sOamData_RotatingPokeBall,
.anims = sSpriteAnimTable_RotatingPokeBall,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_RotatingPokeBall,
};
static const struct SpriteTemplate sSeenOwnTextSpriteTemplate =
{
.tileTag = TAG_DEX_INTERFACE,
.paletteTag = TAG_DEX_INTERFACE,
.oam = &sOamData_SeenOwnText,
.anims = sSpriteAnimTable_SeenOwnText,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_SeenOwnInfo,
};
static const struct SpriteTemplate sHoennNationalTextSpriteTemplate =
{
.tileTag = TAG_DEX_INTERFACE,
.paletteTag = TAG_DEX_INTERFACE,
.oam = &sOamData_InterfaceText,
.anims = sSpriteAnimTable_HoennNationalText,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_SeenOwnInfo,
};
static const struct SpriteTemplate sHoennDexSeenOwnNumberSpriteTemplate =
{
.tileTag = TAG_DEX_INTERFACE,
.paletteTag = TAG_DEX_INTERFACE,
.oam = &sOamData_Dex8x16,
.anims = sSpriteAnimTable_HoennSeenOwnNumber,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_SeenOwnInfo,
};
static const struct SpriteTemplate sNationalDexSeenOwnNumberSpriteTemplate =
{
.tileTag = TAG_DEX_INTERFACE,
.paletteTag = TAG_DEX_INTERFACE,
.oam = &sOamData_Dex8x16,
.anims = sSpriteAnimTable_NationalSeenOwnNumber,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_SeenOwnInfo,
};
static const struct SpriteTemplate sDexListStartMenuCursorSpriteTemplate =
{
.tileTag = TAG_DEX_INTERFACE,
.paletteTag = TAG_DEX_INTERFACE,
.oam = &sOamData_Dex8x16,
.anims = sSpriteAnimTable_DexListStartMenuCursor,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_DexListStartMenuCursor,
};
static const struct CompressedSpriteSheet sInterfaceSpriteSheet[] =
{
{sPokedexPlusHGSS_Interface_Gfx, 0x2000, TAG_DEX_INTERFACE},
{sPokedexPlusHGSS_Interface_DECA_Gfx, 0x2000, TAG_DEX_INTERFACE},
{0}
};
static const struct SpritePalette sInterfaceSpritePalette[] =
{
{sPokedexPlusHGSS_Default_Pal, TAG_DEX_INTERFACE},
{0}
};
// By scroll speed. Last element of each unused
static const u8 sScrollMonIncrements[] = {4, 8, 16, 32, 32};
static const u8 sScrollTimers[] = {8, 4, 2, 1, 1};
static const struct BgTemplate sPokedex_BgTemplate[] =
{
{
.bg = 0,
.charBaseIndex = 0,
.mapBaseIndex = 12,
.screenSize = 0,
.paletteMode = 0,
.priority = 0,
.baseTile = 0
},
{
.bg = 1,
.charBaseIndex = 0,
.mapBaseIndex = 13,
.screenSize = 0,
.paletteMode = 0,
.priority = 1,
.baseTile = 0
},
{
.bg = 2,
.charBaseIndex = 2,
.mapBaseIndex = 14,
.screenSize = 0,
.paletteMode = 0,
.priority = 2,
.baseTile = 0
},
{
.bg = 3,
.charBaseIndex = 0,
.mapBaseIndex = 15,
.screenSize = 0,
.paletteMode = 0,
.priority = 3,
.baseTile = 0
}
};
static const struct WindowTemplate sPokemonList_WindowTemplate[] =
{
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 0,
.width = 32,
.height = 32,
.paletteNum = 0,
.baseBlock = 1,
},
DUMMY_WIN_TEMPLATE
};
static const struct BgTemplate sInfoScreen_BgTemplate[] =
{
{
.bg = 0,
.charBaseIndex = 2,
.mapBaseIndex = 12,
.screenSize = 0,
.paletteMode = 0,
.priority = 3,
.baseTile = 0
},
{
.bg = 1,
.charBaseIndex = 0,
.mapBaseIndex = 13,
.screenSize = 0,
.paletteMode = 0,
.priority = 0,
.baseTile = 0
},
{
.bg = 2,
.charBaseIndex = 2,
.mapBaseIndex = 14,
.screenSize = 0,
.paletteMode = 0,
.priority = 1,
.baseTile = 0
},
{
.bg = 3,
.charBaseIndex = 0,
.mapBaseIndex = 15,
.screenSize = 0,
.paletteMode = 0,
.priority = 2,
.baseTile = 0
}
};
#define WIN_INFO 0
#define WIN_FOOTPRINT 1
#define WIN_CRY_WAVE 2
#define WIN_VU_METER 3
#define WIN_NAVIGATION_BUTTONS 4
static const struct WindowTemplate sInfoScreen_WindowTemplates[] =
{
[WIN_INFO] =
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 0,
.width = 32,
.height = 20,
.paletteNum = 0,
.baseBlock = 1,
},
[WIN_FOOTPRINT] =
{
.bg = 2,
.tilemapLeft = 15, //HGSSS_Ui
.tilemapTop = 7, //HGSSS_Ui
.width = 2,
.height = 2,
.paletteNum = 15,
.baseBlock = 641,
},
[WIN_CRY_WAVE] =
{
.bg = 0,
.tilemapLeft = 0,
.tilemapTop = 12,
.width = 32,
.height = 7,
.paletteNum = 8,
.baseBlock = 645,
},
[WIN_VU_METER] =
{
.bg = 2,
.tilemapLeft = 18,
.tilemapTop = 3,
.width = 10,
.height = 8,
.paletteNum = 9,
.baseBlock = 869,
},
[WIN_NAVIGATION_BUTTONS] =
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 18,
.width = 20,
.height = 2,
.paletteNum = 15,
.baseBlock = 641,
},
DUMMY_WIN_TEMPLATE
};
#define WIN_STATS_TOPBAR 0
#define WIN_STATS_SIDEBAR 1
#define WIN_STATS_NAME_GENDER 2
#define WIN_STATS_LEFT 3
#define WIN_STATS_NAVIGATION_BUTTONS 4
#define WIN_STATS_MOVES_TOP 5
#define WIN_STATS_MOVES_DESCRIPTION 7
#define WIN_STATS_MOVES_BOTTOM 8
#define WIN_STATS_ABILITIES 9
#define WIN_STATS_LEFT_UNUSED 10
#define WIN_STATS_END WIN_STATS_LEFT_UNUSED
static const struct WindowTemplate sStatsScreen_WindowTemplates[] =
{
[WIN_STATS_TOPBAR] =
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 0,
.width = 30,
.height = 2,
.paletteNum = 0,
.baseBlock = 1,
},
[WIN_STATS_SIDEBAR] =
{
.bg = 2,
.tilemapLeft = 30,
.tilemapTop = 0,
.width = 2,
.height = 20,
.paletteNum = 0,
.baseBlock = 1 + 60,
},
[WIN_STATS_NAME_GENDER] =
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 2,
.width = 12,
.height = 4,
.paletteNum = 0,
.baseBlock = 1 + 60 + 40,
},
[WIN_STATS_LEFT] =
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 6,
.width = 12,
.height = 8,
.paletteNum = 0,
.baseBlock = 1 + 60 + 40 + 48,
},
[WIN_STATS_NAVIGATION_BUTTONS] =
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 18,
.width = 12,
.height = 2,
.paletteNum = 15,
.baseBlock = 1 + 60 + 40 + 48 + 96,
},
[WIN_STATS_MOVES_TOP] =
{
.bg = 2,
.tilemapLeft = 12,
.tilemapTop = 2,
.width = 18,
.height = 4,
.paletteNum = 0,
.baseBlock = 1 + 60 + 40 + 48 + 96 + 24,
},
[WIN_STATS_MOVES_DESCRIPTION] =
{
.bg = 2,
.tilemapLeft = 12,
.tilemapTop = 6,
.width = 18,
.height = 4,
.paletteNum = 0,
.baseBlock = 1 + 60 + 40 + 48 + 96 + 24 + 72,
},
[WIN_STATS_MOVES_BOTTOM] =
{
.bg = 2,
.tilemapLeft = 12,
.tilemapTop = 10,
.width = 18,
.height = 2,
.paletteNum = 0,
.baseBlock = 1 + 60 + 40 + 48 + 96 + 24 + 72 + 72,
},
[WIN_STATS_ABILITIES] =
{
.bg = 2,
.tilemapLeft = 12,
.tilemapTop = 12,
.width = 18,
.height = 8,
.paletteNum = 0,
.baseBlock = 1 + 60 + 40 + 48 + 96 + 24 + 72 + 72 + 36,
},
[WIN_STATS_LEFT_UNUSED] =
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 14,
.width = 12,
.height = 4,
.paletteNum = 0,
.baseBlock = 1 + 60 + 40 + 48 + 96 + 24 + 72 + 72 + 36 + 144,
},
DUMMY_WIN_TEMPLATE
};
static const struct BgTemplate sNewEntryInfoScreen_BgTemplate[] =
{
{
.bg = 2,
.charBaseIndex = 2,
.mapBaseIndex = 14,
.screenSize = 0,
.paletteMode = 0,
.priority = 2,
.baseTile = 0
},
{
.bg = 3,
.charBaseIndex = 1,
.mapBaseIndex = 15,
.screenSize = 0,
.paletteMode = 0,
.priority = 3,
.baseTile = 0
},
};
static const struct WindowTemplate sNewEntryInfoScreen_WindowTemplates[] =
{
[WIN_INFO] =
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 0,
.width = 32,
.height = 20,
.paletteNum = 0,
.baseBlock = 1,
},
[WIN_FOOTPRINT] =
{
.bg = 2,
.tilemapLeft = 15, //HGSSS_Ui
.tilemapTop = 7, //HGSSS_Ui
.width = 2,
.height = 2,
.paletteNum = 15,
.baseBlock = 641,
},
DUMMY_WIN_TEMPLATE
};
// First character in range followed by number of characters in range for upper and lowercase
static const u8 sLetterSearchRanges[][4] =
{
{}, // Name not specified, shouldn't be reached
[NAME_ABC] = {CHAR_A, 3, CHAR_a, 3},
[NAME_DEF] = {CHAR_D, 3, CHAR_d, 3},
[NAME_GHI] = {CHAR_G, 3, CHAR_g, 3},
[NAME_JKL] = {CHAR_J, 3, CHAR_j, 3},
[NAME_MNO] = {CHAR_M, 3, CHAR_m, 3},
[NAME_PQR] = {CHAR_P, 3, CHAR_p, 3},
[NAME_STU] = {CHAR_S, 3, CHAR_s, 3},
[NAME_VWX] = {CHAR_V, 3, CHAR_v, 3},
[NAME_YZ] = {CHAR_Y, 2, CHAR_y, 2},
};
#define LETTER_IN_RANGE_UPPER(letter, range) \
((letter) >= sLetterSearchRanges[range][0] \
&& (letter) < sLetterSearchRanges[range][0] + sLetterSearchRanges[range][1]) \
#define LETTER_IN_RANGE_LOWER(letter, range) \
((letter) >= sLetterSearchRanges[range][2] \
&& (letter) < sLetterSearchRanges[range][2] + sLetterSearchRanges[range][3]) \
static const struct SearchMenuTopBarItem sSearchMenuTopBarItems[SEARCH_TOPBAR_COUNT] =
{
[SEARCH_TOPBAR_SEARCH] =
{
.description = gText_SearchForPkmnBasedOnParameters,
.highlightX = 0,
.highlightY = 0,
.highlightWidth = 5,
},
[SEARCH_TOPBAR_SHIFT] =
{
.description = gText_SwitchPokedexListings,
.highlightX = 6,
.highlightY = 0,
.highlightWidth = 5,
},
[SEARCH_TOPBAR_CANCEL] =
{
.description = gText_ReturnToPokedex,
.highlightX = 12,
.highlightY = 0,
.highlightWidth = 5,
},
};
static const struct SearchMenuItem sSearchMenuItems[SEARCH_COUNT] =
{
[SEARCH_NAME] =
{
.description = gText_ListByFirstLetter,
.titleBgX = 0,
.titleBgY = 2,
.titleBgWidth = 5,
.selectionBgX = 5,
.selectionBgY = 2,
.selectionBgWidth = 12,
},
[SEARCH_COLOR] =
{
.description = gText_ListByBodyColor,
.titleBgX = 0,
.titleBgY = 4,
.titleBgWidth = 5,
.selectionBgX = 5,
.selectionBgY = 4,
.selectionBgWidth = 12,
},
[SEARCH_TYPE_LEFT] =
{
.description = gText_ListByType,
.titleBgX = 0,
.titleBgY = 6,
.titleBgWidth = 5,
.selectionBgX = 5,
.selectionBgY = 6,
.selectionBgWidth = 6,
},
[SEARCH_TYPE_RIGHT] =
{
.description = gText_ListByType,
.titleBgX = 0,
.titleBgY = 6,
.titleBgWidth = 5,
.selectionBgX = 11,
.selectionBgY = 6,
.selectionBgWidth = 6,
},
[SEARCH_ORDER] =
{
.description = gText_SelectPokedexListingMode,
.titleBgX = 0,
.titleBgY = 8,
.titleBgWidth = 5,
.selectionBgX = 5,
.selectionBgY = 8,
.selectionBgWidth = 12,
},
[SEARCH_MODE] =
{
.description = gText_SelectPokedexMode,
.titleBgX = 0,
.titleBgY = 10,
.titleBgWidth = 5,
.selectionBgX = 5,
.selectionBgY = 10,
.selectionBgWidth = 12,
},
[SEARCH_OK] =
{
.description = gText_ExecuteSearchSwitch,
.titleBgX = 0,
.titleBgY = 12,
.titleBgWidth = 5,
.selectionBgX = 0,
.selectionBgY = 0,
.selectionBgWidth = 0,
},
};
// Left, Right, Up, Down
static const u8 sSearchMovementMap_SearchNatDex[SEARCH_COUNT][4] =
{
[SEARCH_NAME] =
{
0xFF,
0xFF,
0xFF,
SEARCH_COLOR
},
[SEARCH_COLOR] =
{
0xFF,
0xFF,
SEARCH_NAME,
SEARCH_TYPE_LEFT
},
[SEARCH_TYPE_LEFT] =
{
0xFF,
SEARCH_TYPE_RIGHT,
SEARCH_COLOR,
SEARCH_ORDER
},
[SEARCH_TYPE_RIGHT] =
{ SEARCH_TYPE_LEFT,
0xFF,
SEARCH_COLOR,
SEARCH_ORDER
},
[SEARCH_ORDER] =
{
0xFF,
0xFF,
SEARCH_TYPE_LEFT,
SEARCH_MODE
},
[SEARCH_MODE] =
{
0xFF,
0xFF,
SEARCH_ORDER,
SEARCH_OK
},
[SEARCH_OK] =
{
0xFF,
0xFF,
SEARCH_MODE,
0xFF
},
};
// Left, Right, Up, Down
static const u8 sSearchMovementMap_ShiftNatDex[SEARCH_COUNT][4] =
{
[SEARCH_NAME] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_COLOR] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_TYPE_LEFT] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_TYPE_RIGHT] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_ORDER] =
{
0xFF,
0xFF,
0xFF,
SEARCH_MODE
},
[SEARCH_MODE] =
{
0xFF,
0xFF,
SEARCH_ORDER,
SEARCH_OK
},
[SEARCH_OK] =
{
0xFF,
0xFF,
SEARCH_MODE,
0xFF
},
};
// Left, Right, Up, Down
static const u8 sSearchMovementMap_SearchHoennDex[SEARCH_COUNT][4] =
{
[SEARCH_NAME] =
{
0xFF,
0xFF,
0xFF,
SEARCH_COLOR
},
[SEARCH_COLOR] =
{
0xFF,
0xFF,
SEARCH_NAME,
SEARCH_TYPE_LEFT
},
[SEARCH_TYPE_LEFT] =
{
0xFF,
SEARCH_TYPE_RIGHT,
SEARCH_COLOR,
SEARCH_ORDER
},
[SEARCH_TYPE_RIGHT] =
{ SEARCH_TYPE_LEFT,
0xFF,
SEARCH_COLOR,
SEARCH_ORDER
},
[SEARCH_ORDER] =
{
0xFF,
0xFF,
SEARCH_TYPE_LEFT,
SEARCH_OK
},
[SEARCH_MODE] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_OK] =
{
0xFF,
0xFF,
SEARCH_ORDER,
0xFF
},
};
// Left, Right, Up, Down
static const u8 sSearchMovementMap_ShiftHoennDex[SEARCH_COUNT][4] =
{
[SEARCH_NAME] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_COLOR] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_TYPE_LEFT] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_TYPE_RIGHT] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_ORDER] =
{
0xFF,
0xFF,
0xFF,
SEARCH_OK
},
[SEARCH_MODE] =
{
0xFF,
0xFF,
0xFF,
0xFF
},
[SEARCH_OK] =
{
0xFF,
0xFF,
SEARCH_ORDER,
0xFF
},
};
static const struct SearchOptionText sDexModeOptions[] =
{
[DEX_MODE_HOENN] = {gText_DexHoennDescription, gText_DexHoennTitle},
[DEX_MODE_NATIONAL] = {gText_DexNatDescription, gText_DexNatTitle},
{},
};
static const struct SearchOptionText sDexOrderOptions[] =
{
[ORDER_NUMERICAL] = {gText_DexSortNumericalDescription, gText_DexSortNumericalTitle},
[ORDER_ALPHABETICAL] = {gText_DexSortAtoZDescription, gText_DexSortAtoZTitle},
[ORDER_HEAVIEST] = {gText_DexSortHeaviestDescription, gText_DexSortHeaviestTitle},
[ORDER_LIGHTEST] = {gText_DexSortLightestDescription, gText_DexSortLightestTitle},
[ORDER_TALLEST] = {gText_DexSortTallestDescription, gText_DexSortTallestTitle},
[ORDER_SMALLEST] = {gText_DexSortSmallestDescription, gText_DexSortSmallestTitle},
{},
};
static const struct SearchOptionText sDexSearchNameOptions[] =
{
{gText_DexEmptyString, gText_DexSearchDontSpecify},
[NAME_ABC] = {gText_DexEmptyString, gText_DexSearchAlphaABC},
[NAME_DEF] = {gText_DexEmptyString, gText_DexSearchAlphaDEF},
[NAME_GHI] = {gText_DexEmptyString, gText_DexSearchAlphaGHI},
[NAME_JKL] = {gText_DexEmptyString, gText_DexSearchAlphaJKL},
[NAME_MNO] = {gText_DexEmptyString, gText_DexSearchAlphaMNO},
[NAME_PQR] = {gText_DexEmptyString, gText_DexSearchAlphaPQR},
[NAME_STU] = {gText_DexEmptyString, gText_DexSearchAlphaSTU},
[NAME_VWX] = {gText_DexEmptyString, gText_DexSearchAlphaVWX},
[NAME_YZ] = {gText_DexEmptyString, gText_DexSearchAlphaYZ},
{},
};
static const struct SearchOptionText sDexSearchColorOptions[] =
{
{gText_DexEmptyString, gText_DexSearchDontSpecify},
[BODY_COLOR_RED + 1] = {gText_DexEmptyString, gText_DexSearchColorRed},
[BODY_COLOR_BLUE + 1] = {gText_DexEmptyString, gText_DexSearchColorBlue},
[BODY_COLOR_YELLOW + 1] = {gText_DexEmptyString, gText_DexSearchColorYellow},
[BODY_COLOR_GREEN + 1] = {gText_DexEmptyString, gText_DexSearchColorGreen},
[BODY_COLOR_BLACK + 1] = {gText_DexEmptyString, gText_DexSearchColorBlack},
[BODY_COLOR_BROWN + 1] = {gText_DexEmptyString, gText_DexSearchColorBrown},
[BODY_COLOR_PURPLE + 1] = {gText_DexEmptyString, gText_DexSearchColorPurple},
[BODY_COLOR_GRAY + 1] = {gText_DexEmptyString, gText_DexSearchColorGray},
[BODY_COLOR_WHITE + 1] = {gText_DexEmptyString, gText_DexSearchColorWhite},
[BODY_COLOR_PINK + 1] = {gText_DexEmptyString, gText_DexSearchColorPink},
{},
};
static const struct SearchOptionText sDexSearchTypeOptions[] =
{
{gText_DexEmptyString, gTypesInfo[TYPE_NONE].name},
{gText_DexEmptyString, gTypesInfo[TYPE_NORMAL].name},
{gText_DexEmptyString, gTypesInfo[TYPE_FIGHTING].name},
{gText_DexEmptyString, gTypesInfo[TYPE_FLYING].name},
{gText_DexEmptyString, gTypesInfo[TYPE_POISON].name},
{gText_DexEmptyString, gTypesInfo[TYPE_GROUND].name},
{gText_DexEmptyString, gTypesInfo[TYPE_ROCK].name},
{gText_DexEmptyString, gTypesInfo[TYPE_BUG].name},
{gText_DexEmptyString, gTypesInfo[TYPE_GHOST].name},
{gText_DexEmptyString, gTypesInfo[TYPE_STEEL].name},
{gText_DexEmptyString, gTypesInfo[TYPE_FIRE].name},
{gText_DexEmptyString, gTypesInfo[TYPE_WATER].name},
{gText_DexEmptyString, gTypesInfo[TYPE_GRASS].name},
{gText_DexEmptyString, gTypesInfo[TYPE_ELECTRIC].name},
{gText_DexEmptyString, gTypesInfo[TYPE_PSYCHIC].name},
{gText_DexEmptyString, gTypesInfo[TYPE_ICE].name},
{gText_DexEmptyString, gTypesInfo[TYPE_DRAGON].name},
{gText_DexEmptyString, gTypesInfo[TYPE_DARK].name},
{gText_DexEmptyString, gTypesInfo[TYPE_FAIRY].name},
{},
};
static const u8 sPokedexModes[] = {DEX_MODE_HOENN, DEX_MODE_NATIONAL};
static const u8 sOrderOptions[] =
{
ORDER_NUMERICAL,
ORDER_ALPHABETICAL,
ORDER_HEAVIEST,
ORDER_LIGHTEST,
ORDER_TALLEST,
ORDER_SMALLEST,
};
static const u8 sDexSearchTypeIds[NUMBER_OF_MON_TYPES] =
{
TYPE_NONE,
TYPE_NORMAL,
TYPE_FIGHTING,
TYPE_FLYING,
TYPE_POISON,
TYPE_GROUND,
TYPE_ROCK,
TYPE_BUG,
TYPE_GHOST,
TYPE_STEEL,
TYPE_FIRE,
TYPE_WATER,
TYPE_GRASS,
TYPE_ELECTRIC,
TYPE_PSYCHIC,
TYPE_ICE,
TYPE_DRAGON,
TYPE_DARK,
TYPE_FAIRY,
};
// Number pairs are the task data for tracking the cursor pos and scroll offset of each option list
// See task data defines above Task_LoadSearchMenu
static const struct SearchOption sSearchOptions[] =
{
[SEARCH_NAME] = {sDexSearchNameOptions, 6, 7, ARRAY_COUNT(sDexSearchNameOptions) - 1},
[SEARCH_COLOR] = {sDexSearchColorOptions, 8, 9, ARRAY_COUNT(sDexSearchColorOptions) - 1},
[SEARCH_TYPE_LEFT] = {sDexSearchTypeOptions, 10, 11, ARRAY_COUNT(sDexSearchTypeOptions) - 1},
[SEARCH_TYPE_RIGHT] = {sDexSearchTypeOptions, 12, 13, ARRAY_COUNT(sDexSearchTypeOptions) - 1},
[SEARCH_ORDER] = {sDexOrderOptions, 4, 5, ARRAY_COUNT(sDexOrderOptions) - 1},
[SEARCH_MODE] = {sDexModeOptions, 2, 3, ARRAY_COUNT(sDexModeOptions) - 1},
};
static const struct BgTemplate sSearchMenu_BgTemplate[] =
{
{
.bg = 0,
.charBaseIndex = 2,
.mapBaseIndex = 12,
.screenSize = 0,
.paletteMode = 0,
.priority = 0,
.baseTile = 0
},
{
.bg = 1,
.charBaseIndex = 0,
.mapBaseIndex = 13,
.screenSize = 0,
.paletteMode = 0,
.priority = 1,
.baseTile = 0
},
{
.bg = 2,
.charBaseIndex = 2,
.mapBaseIndex = 14,
.screenSize = 0,
.paletteMode = 0,
.priority = 2,
.baseTile = 0
},
{
.bg = 3,
.charBaseIndex = 0,
.mapBaseIndex = 15,
.screenSize = 0,
.paletteMode = 0,
.priority = 3,
.baseTile = 0
}
};
static const struct WindowTemplate sSearchMenu_WindowTemplate[] =
{
{
.bg = 2,
.tilemapLeft = 0,
.tilemapTop = 0,
.width = 32,
.height = 20,
.paletteNum = 0,
.baseBlock = 0x0001,
},
DUMMY_WIN_TEMPLATE
};
//************************************
//* *
//* MAIN *
//* *
//************************************
void CB2_OpenPokedexPlusHGSS(void)
{
if (!POKEDEX_PLUS_HGSS) return; // prevents the compiler from emitting static .rodata
// if the feature is disabled
switch (gMain.state)
{
case 0:
default:
SetVBlankCallback(NULL);
ResetOtherVideoRegisters(0);
DmaFillLarge16(3, 0, (u8 *)VRAM, VRAM_SIZE, 0x1000);
DmaClear32(3, OAM, OAM_SIZE);
DmaClear16(3, PLTT, PLTT_SIZE);
gMain.state = 1;
break;
case 1:
ScanlineEffect_Stop();
ResetTasks();
ResetSpriteData();
ResetPaletteFade();
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 8;
ResetAllPicSprites();
gMain.state++;
break;
case 2:
sPokedexView = AllocZeroed(sizeof(struct PokedexView));
ResetPokedexView(sPokedexView);
CreateTask(Task_OpenPokedexMainPage, 0);
sPokedexView->dexMode = gSaveBlock2Ptr->pokedex.mode;
if (!IsNationalPokedexEnabled())
sPokedexView->dexMode = DEX_MODE_HOENN;
sPokedexView->dexOrder = gSaveBlock2Ptr->pokedex.order;
sPokedexView->selectedPokemon = sLastSelectedPokemon;
sPokedexView->pokeBallRotation = sPokeBallRotation;
sPokedexView->selectedScreen = AREA_SCREEN;
if (!IsNationalPokedexEnabled())
{
sPokedexView->seenCount = GetHoennPokedexCount(FLAG_GET_SEEN);
sPokedexView->ownCount = GetHoennPokedexCount(FLAG_GET_CAUGHT);
}
else
{
sPokedexView->seenCount = GetNationalPokedexCount(FLAG_GET_SEEN);
sPokedexView->ownCount = GetNationalPokedexCount(FLAG_GET_CAUGHT);
}
sPokedexView->initialVOffset = 8;
gMain.state++;
break;
case 3:
EnableInterrupts(1);
SetVBlankCallback(VBlankCB_Pokedex);
SetMainCallback2(CB2_Pokedex);
CreatePokedexList(sPokedexView->dexMode, sPokedexView->dexOrder);
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x80);
break;
}
}
static void ResetPokedexView(struct PokedexView *pokedexView)
{
u16 i;
for (i = 0; i < NATIONAL_DEX_COUNT; i++)
{
pokedexView->pokedexList[i].dexNum = 0xFFFF;
pokedexView->pokedexList[i].seen = FALSE;
pokedexView->pokedexList[i].owned = FALSE;
}
pokedexView->pokedexList[NATIONAL_DEX_COUNT].dexNum = 0;
pokedexView->pokedexList[NATIONAL_DEX_COUNT].seen = FALSE;
pokedexView->pokedexList[NATIONAL_DEX_COUNT].owned = FALSE;
pokedexView->pokemonListCount = 0;
pokedexView->selectedPokemon = 0;
pokedexView->selectedPokemonBackup = 0;
pokedexView->dexMode = DEX_MODE_HOENN;
pokedexView->dexModeBackup = DEX_MODE_HOENN;
pokedexView->dexOrder = ORDER_NUMERICAL;
pokedexView->dexOrderBackup = ORDER_NUMERICAL;
pokedexView->seenCount = 0;
pokedexView->ownCount = 0;
for (i = 0; i < MAX_MONS_ON_SCREEN; i++)
pokedexView->monSpriteIds[i] = 0xFFFF;
pokedexView->pokeBallRotationStep = 0;
pokedexView->pokeBallRotationBackup = 0;
pokedexView->pokeBallRotation = 0;
pokedexView->initialVOffset = 0;
pokedexView->scrollTimer = 0;
pokedexView->scrollDirection = 0;
pokedexView->listVOffset = 0;
pokedexView->listMovingVOffset = 0;
pokedexView->scrollMonIncrement = 0;
pokedexView->maxScrollTimer = 0;
pokedexView->scrollSpeed = 0;
for (i = 0; i < ARRAY_COUNT(pokedexView->unkArr1); i++)
pokedexView->unkArr1[i] = 0;
pokedexView->currentPage = PAGE_MAIN;
pokedexView->currentPageBackup = PAGE_MAIN;
pokedexView->isSearchResults = FALSE;
pokedexView->selectedScreen = AREA_SCREEN;
pokedexView->screenSwitchState = 0;
pokedexView->menuIsOpen = 0;
pokedexView->menuCursorPos = 0;
pokedexView->menuY = 0;
for (i = 0; i < ARRAY_COUNT(pokedexView->unkArr2); i++)
pokedexView->unkArr2[i] = 0;
for (i = 0; i < ARRAY_COUNT(pokedexView->unkArr3); i++)
pokedexView->unkArr3[i] = 0;
pokedexView->originalSearchSelectionNum = 0;
}
static void VBlankCB_Pokedex(void)
{
LoadOam();
ProcessSpriteCopyRequests();
TransferPlttBuffer();
}
static void CB2_Pokedex(void)
{
RunTasks();
AnimateSprites();
BuildOamBuffer();
UpdatePaletteFade();
}
static void Task_OpenPokedexMainPage(u8 taskId)
{
sPokedexView->isSearchResults = FALSE;
sPokedexView->sEvoScreenData.fromEvoPage = FALSE;
sPokedexView->formSpecies = 0;
if (LoadPokedexListPage(PAGE_MAIN))
gTasks[taskId].func = Task_HandlePokedexInput;
}
#define tLoadScreenTaskId data[0]
static void Task_HandlePokedexInput(u8 taskId)
{
SetGpuReg(REG_OFFSET_BG0VOFS, sPokedexView->menuY);
if (sPokedexView->menuY)
{
sPokedexView->menuY -= 8;
if (sPokedexView->menuIsOpen == FALSE && sPokedexView->menuY == 8)
{
CreateStatBars(&sPokedexView->pokedexList[sPokedexView->selectedPokemon]);
CreateStatBarsBg();
}
}
else
{
if (JOY_NEW(A_BUTTON) && sPokedexView->pokedexList[sPokedexView->selectedPokemon].seen)
{
TryDestroyStatBars();
UpdateSelectedMonSpriteId();
BeginNormalPaletteFade(~(1 << (gSprites[sPokedexView->selectedMonSpriteId].oam.paletteNum + 16)), 0, 0, 0x10, RGB_BLACK);
gSprites[sPokedexView->selectedMonSpriteId].callback = SpriteCB_MoveMonForInfoScreen;
gTasks[taskId].func = Task_OpenInfoScreenAfterMonMovement;
PlaySE(SE_PIN);
FreeWindowAndBgBuffers();
}
else if (JOY_NEW(START_BUTTON))
{
TryDestroyStatBars();
TryDestroyStatBarsBg();
sPokedexView->menuY = 0;
sPokedexView->menuIsOpen = TRUE;
sPokedexView->menuCursorPos = 0;
gTasks[taskId].func = Task_HandlePokedexStartMenuInput;
PlaySE(SE_SELECT);
}
else if (JOY_NEW(SELECT_BUTTON))
{
PlaySE(SE_SELECT);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
gTasks[taskId].tLoadScreenTaskId = LoadSearchMenu();
sPokedexView->screenSwitchState = 0;
sPokedexView->pokeBallRotationBackup = sPokedexView->pokeBallRotation;
sPokedexView->selectedPokemonBackup = sPokedexView->selectedPokemon;
sPokedexView->dexModeBackup = sPokedexView->dexMode;
sPokedexView->dexOrderBackup = sPokedexView->dexOrder;
gTasks[taskId].func = Task_WaitForExitSearch;
PlaySE(SE_PC_LOGIN);
FreeWindowAndBgBuffers();
}
else if (JOY_NEW(B_BUTTON))
{
TryDestroyStatBars();
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
gTasks[taskId].func = Task_ClosePokedex;
PlaySE(SE_PC_OFF);
}
else
{
//Handle D-pad
sPokedexView->selectedPokemon = TryDoPokedexScroll(sPokedexView->selectedPokemon, 0xE);
if (sPokedexView->scrollTimer)
gTasks[taskId].func = Task_WaitForScroll;
else if (!sPokedexView->scrollTimer && !sPokedexView->scrollSpeed &&sPokedexView->justScrolled)
CreateStatBars(&sPokedexView->pokedexList[sPokedexView->selectedPokemon]);
}
}
}
static void Task_WaitForScroll(u8 taskId)
{
TryDestroyStatBars();
if (UpdateDexListScroll(sPokedexView->scrollDirection, sPokedexView->scrollMonIncrement, sPokedexView->maxScrollTimer))
gTasks[taskId].func = Task_HandlePokedexInput;
}
static void Task_HandlePokedexStartMenuInput(u8 taskId)
{
SetGpuReg(REG_OFFSET_BG0VOFS, sPokedexView->menuY);
//If menu is not open, slide it up, on screen
if (sPokedexView->menuY != 80)
{
sPokedexView->menuY += 8;
}
else
{
if (JOY_NEW(A_BUTTON))
{
switch (sPokedexView->menuCursorPos)
{
case 0: //BACK TO LIST
default:
gMain.newKeys |= START_BUTTON; //Exit menu
break;
case 1: //LIST TOP
sPokedexView->selectedPokemon = 0;
sPokedexView->pokeBallRotation = POKEBALL_ROTATION_TOP;
ClearMonSprites();
CreateMonSpritesAtPos(sPokedexView->selectedPokemon, 0xE);
gMain.newKeys |= START_BUTTON; //Exit menu
break;
case 2: //LIST BOTTOM
sPokedexView->selectedPokemon = sPokedexView->pokemonListCount - 1;
sPokedexView->pokeBallRotation = sPokedexView->pokemonListCount * 16 + POKEBALL_ROTATION_BOTTOM;
ClearMonSprites();
CreateMonSpritesAtPos(sPokedexView->selectedPokemon, 0xE);
gMain.newKeys |= START_BUTTON; //Exit menu
break;
case 3: //CLOSE POKEDEX
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
gTasks[taskId].func = Task_ClosePokedex;
PlaySE(SE_PC_OFF);
break;
}
}
//Exit menu when Start or B is pressed
if (JOY_NEW(START_BUTTON | B_BUTTON))
{
sPokedexView->menuIsOpen = FALSE;
gTasks[taskId].func = Task_HandlePokedexInput;
PlaySE(SE_SELECT);
}
else if (JOY_REPEAT(DPAD_UP) && sPokedexView->menuCursorPos != 0)
{
sPokedexView->menuCursorPos--;
PlaySE(SE_SELECT);
}
else if (JOY_REPEAT(DPAD_DOWN) && sPokedexView->menuCursorPos < 3)
{
sPokedexView->menuCursorPos++;
PlaySE(SE_SELECT);
}
}
}
// Opening the info screen from list view. Pokémon sprite is moving to its new position, wait for it to arrive
static void Task_OpenInfoScreenAfterMonMovement(u8 taskId)
{
if (gSprites[sPokedexView->selectedMonSpriteId].x == MON_PAGE_X && gSprites[sPokedexView->selectedMonSpriteId].y == MON_PAGE_Y)
{
sPokedexView->currentPageBackup = sPokedexView->currentPage;
gTasks[taskId].tLoadScreenTaskId = LoadInfoScreen(&sPokedexView->pokedexList[sPokedexView->selectedPokemon], sPokedexView->selectedMonSpriteId);
gTasks[taskId].func = Task_WaitForExitInfoScreen;
}
}
static void Task_WaitForExitInfoScreen(u8 taskId)
{
if (gTasks[gTasks[taskId].tLoadScreenTaskId].isActive)
{
// While active, handle scroll input
if (sPokedexView->currentPage == PAGE_INFO && !IsInfoScreenScrolling(gTasks[taskId].tLoadScreenTaskId) && TryDoInfoScreenScroll())
StartInfoScreenScroll(&sPokedexView->pokedexList[sPokedexView->selectedPokemon], gTasks[taskId].tLoadScreenTaskId);
}
else
{
// Exiting, back to list view
sLastSelectedPokemon = sPokedexView->selectedPokemon;
sPokeBallRotation = sPokedexView->pokeBallRotation;
gTasks[taskId].func = Task_OpenPokedexMainPage;
}
}
static void Task_ClosePokedex(u8 taskId)
{
if (!gPaletteFade.active)
{
gSaveBlock2Ptr->pokedex.mode = sPokedexView->dexMode;
if (!IsNationalPokedexEnabled())
gSaveBlock2Ptr->pokedex.mode = DEX_MODE_HOENN;
gSaveBlock2Ptr->pokedex.order = sPokedexView->dexOrder;
ClearMonSprites();
FreeWindowAndBgBuffers();
DestroyTask(taskId);
SetMainCallback2(CB2_ReturnToFieldWithOpenMenu);
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100);
Free(sPokedexView);
}
}
static void LoadPokedexBgPalette(bool8 isSearchResults)
{
if (!HGSS_DARK_MODE)
{
if (isSearchResults == TRUE)
LoadPalette(sPokedexPlusHGSS_SearchResults_Pal + 1, BG_PLTT_ID(0) + 1, PLTT_SIZEOF(6 * 16 - 1));
else if (!IsNationalPokedexEnabled())
LoadPalette(sPokedexPlusHGSS_Default_Pal + 1, BG_PLTT_ID(0) + 1, PLTT_SIZEOF(6 * 16 - 1));
else
LoadPalette(sPokedexPlusHGSS_National_Pal + 1, BG_PLTT_ID(0) + 1, PLTT_SIZEOF(6 * 16 - 1));
LoadPalette(GetOverworldTextboxPalettePtr(), 0xF0, 32);
}
else
{
if (isSearchResults == TRUE)
LoadPalette(sPokedexPlusHGSS_SearchResults_dark_Pal + 1, BG_PLTT_ID(0) + 1, PLTT_SIZEOF(6 * 16 - 1));
else if (!IsNationalPokedexEnabled())
LoadPalette(sPokedexPlusHGSS_Default_dark_Pal + 1, BG_PLTT_ID(0) + 1, PLTT_SIZEOF(6 * 16 - 1));
else
LoadPalette(sPokedexPlusHGSS_National_dark_Pal + 1, BG_PLTT_ID(0) + 1, PLTT_SIZEOF(6 * 16 - 1));
LoadPalette(GetOverworldTextboxPalettePtr(), 0xF0, 32);
}
}
//************************************
//* *
//* Main scrolling list screen *
//* *
//************************************
// For loading main pokedex page or pokedex search results
static bool8 LoadPokedexListPage(u8 page)
{
switch (gMain.state)
{
case 0:
default:
if (gPaletteFade.active)
return 0;
SetVBlankCallback(NULL);
sPokedexView->currentPage = page;
ResetOtherVideoRegisters(0);
SetGpuReg(REG_OFFSET_BG2VOFS, sPokedexView->initialVOffset);
ResetBgsAndClearDma3BusyFlags(0);
InitBgsFromTemplates(0, sPokedex_BgTemplate, ARRAY_COUNT(sPokedex_BgTemplate));
SetBgTilemapBuffer(3, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(2, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(1, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(0, AllocZeroed(BG_SCREEN_SIZE));
if (!HGSS_DECAPPED)
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_MenuList_Gfx, 0x2000, 0, 0);
else
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_MenuList_DECA_Gfx, 0x2000, 0, 0);
CopyToBgTilemapBuffer(1, sPokedexPlusHGSS_ScreenList_Tilemap, 0, 0);
CopyToBgTilemapBuffer(3, sPokedexPlusHGSS_ScreenListUnderlay_Tilemap, 0, 0);
if (page == PAGE_MAIN)
CopyToBgTilemapBuffer(0, sPokedexPlusHGSS_StartMenuMain_Tilemap, 0, 0x280);
else
CopyToBgTilemapBuffer(0, sPokedexPlusHGSS_StartMenuSearchResults_Tilemap, 0, 0x280);
ResetPaletteFade();
if (page == PAGE_MAIN)
sPokedexView->isSearchResults = FALSE;
else
sPokedexView->isSearchResults = TRUE;
LoadPokedexBgPalette(sPokedexView->isSearchResults);
InitWindows(sPokemonList_WindowTemplate);
DeactivateAllTextPrinters();
PutWindowTilemap(0);
CopyWindowToVram(0, COPYWIN_FULL);
gMain.state = 1;
break;
case 1:
ResetSpriteData();
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 8;
LoadCompressedSpriteSheet(&sInterfaceSpriteSheet[HGSS_DECAPPED]);
LoadSpritePalettes(sInterfaceSpritePalette);
LoadSpritePalettes(sStatBarSpritePal);
CreateInterfaceSprites(page);
gMain.state++;
break;
case 2:
gMain.state++;
break;
case 3:
if (page == PAGE_MAIN)
CreatePokedexList(sPokedexView->dexMode, sPokedexView->dexOrder);
if (sPokedexView->originalSearchSelectionNum != 0)
{
// when returning to search results after selecting an evo, we have to restore
// the original dexNum because the search results page doesn't rebuild the list
sPokedexListItem->dexNum = sPokedexView->originalSearchSelectionNum;
sPokedexView->originalSearchSelectionNum = 0;
}
CreateMonSpritesAtPos(sPokedexView->selectedPokemon, 0xE);
sPokedexView->statBarsSpriteId = 0xFF; //stat bars
CreateStatBars(&sPokedexView->pokedexList[sPokedexView->selectedPokemon]); //stat bars
sPokedexView->statBarsBgSpriteId = 0xFF; //stat bars background
CreateStatBarsBg(); //stat bars background
sPokedexView->menuIsOpen = FALSE;
sPokedexView->menuY = 0;
CopyBgTilemapBufferToVram(0);
CopyBgTilemapBufferToVram(1);
CopyBgTilemapBufferToVram(2);
CopyBgTilemapBufferToVram(3);
gMain.state++;
break;
case 4:
BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK);
SetVBlankCallback(VBlankCB_Pokedex);
gMain.state++;
break;
case 5:
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_ALL | WININ_WIN1_ALL);
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_ALL | WINOUT_WINOBJ_BG0 | WINOUT_WINOBJ_BG2 | WINOUT_WINOBJ_BG3 | WINOUT_WINOBJ_OBJ);
SetGpuReg(REG_OFFSET_WIN0H, 0);
SetGpuReg(REG_OFFSET_WIN0V, 0);
SetGpuReg(REG_OFFSET_WIN1H, 0);
SetGpuReg(REG_OFFSET_WIN1V, 0);
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON | DISPCNT_OBJWIN_ON);
ShowBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 6:
if (!gPaletteFade.active)
{
gMain.state = 0;
return TRUE;
}
break;
}
return FALSE;
}
static void CreatePokedexList(u8 dexMode, u8 order)
{
u16 vars[3]; //I have no idea why three regular variables are stored in an array, but whatever.
#define temp_dexCount vars[0]
#define temp_isHoennDex vars[1]
#define temp_dexNum vars[2]
s16 i;
sPokedexView->pokemonListCount = 0;
switch (dexMode)
{
default:
case DEX_MODE_HOENN:
temp_dexCount = HOENN_DEX_COUNT;
temp_isHoennDex = TRUE;
break;
case DEX_MODE_NATIONAL:
if (IsNationalPokedexEnabled())
{
temp_dexCount = NATIONAL_DEX_COUNT;
temp_isHoennDex = FALSE;
}
else
{
temp_dexCount = HOENN_DEX_COUNT;
temp_isHoennDex = TRUE;
}
break;
}
switch (order)
{
case ORDER_NUMERICAL:
if (temp_isHoennDex)
{
for (i = 0; i < temp_dexCount; i++)
{
temp_dexNum = HoennToNationalOrder(i + 1);
sPokedexView->pokedexList[i].dexNum = temp_dexNum;
sPokedexView->pokedexList[i].seen = GetSetPokedexFlag(temp_dexNum, FLAG_GET_SEEN);
sPokedexView->pokedexList[i].owned = GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT);
if (sPokedexView->pokedexList[i].seen)
sPokedexView->pokemonListCount = i + 1;
}
}
else
{
s16 r5, r10;
for (i = 0, r5 = 0, r10 = 0; i < temp_dexCount; i++)
{
temp_dexNum = i + 1;
if (GetSetPokedexFlag(temp_dexNum, FLAG_GET_SEEN))
r10 = 1;
if (r10)
{
sPokedexView->pokedexList[r5].dexNum = temp_dexNum;
sPokedexView->pokedexList[r5].seen = GetSetPokedexFlag(temp_dexNum, FLAG_GET_SEEN);
sPokedexView->pokedexList[r5].owned = GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT);
if (sPokedexView->pokedexList[r5].seen)
sPokedexView->pokemonListCount = r5 + 1;
r5++;
}
}
}
break;
case ORDER_ALPHABETICAL:
for (i = 0; i < NATIONAL_DEX_COUNT; i++)
{
temp_dexNum = gPokedexOrder_Alphabetical[i];
if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_SEEN))
{
sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].owned = GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT);
sPokedexView->pokemonListCount++;
}
}
break;
case ORDER_HEAVIEST:
for (i = NATIONAL_DEX_COUNT - 1; i >= 0; i--)
{
temp_dexNum = gPokedexOrder_Weight[i];
if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT))
{
sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].owned = TRUE;
sPokedexView->pokemonListCount++;
}
}
break;
case ORDER_LIGHTEST:
for (i = 0; i < NATIONAL_DEX_COUNT; i++)
{
temp_dexNum = gPokedexOrder_Weight[i];
if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT))
{
sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].owned = TRUE;
sPokedexView->pokemonListCount++;
}
}
break;
case ORDER_TALLEST:
for (i = NATIONAL_DEX_COUNT - 1; i >= 0; i--)
{
temp_dexNum = gPokedexOrder_Height[i];
if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT))
{
sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].owned = TRUE;
sPokedexView->pokemonListCount++;
}
}
break;
case ORDER_SMALLEST:
for (i = 0; i < NATIONAL_DEX_COUNT; i++)
{
temp_dexNum = gPokedexOrder_Height[i];
if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT))
{
sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE;
sPokedexView->pokedexList[sPokedexView->pokemonListCount].owned = TRUE;
sPokedexView->pokemonListCount++;
}
}
break;
}
for (i = sPokedexView->pokemonListCount; i < NATIONAL_DEX_COUNT; i++)
{
sPokedexView->pokedexList[i].dexNum = 0xFFFF;
sPokedexView->pokedexList[i].seen = FALSE;
sPokedexView->pokedexList[i].owned = FALSE;
}
}
static void PrintMonDexNumAndName(u8 windowId, u8 fontId, const u8 *str, u8 left, u8 top)
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_DYNAMIC_COLOR_6;
color[2] = TEXT_COLOR_LIGHT_GRAY;
AddTextPrinterParameterized4(windowId, fontId, left * 8 - 4, (top * 8) + 1, 0, 0, color, TEXT_SKIP_DRAW, str);
}
static void PrintMonDexNumAndName_2(u8 windowId, u8 fontId, const u8* str, u8 left, u8 top) //offset for closer numer + text
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_DYNAMIC_COLOR_6;
color[2] = TEXT_COLOR_LIGHT_GRAY;
AddTextPrinterParameterized4(windowId, fontId, left * 8 - 13, (top * 8) + 1, 0, 0, color, -1, str);
}
// u16 ignored is passed but never used
#define MON_LIST_X 2
static void CreateMonListEntry(u8 position, u16 b, u16 ignored)
{
s16 entryNum;
u16 i;
u16 vOffset;
switch (position)
{
case 0: // Initial
default:
entryNum = b - 5;
for (i = 0; i <= 10; i++)
{
if (entryNum < 0 || entryNum >= NATIONAL_DEX_COUNT || sPokedexView->pokedexList[entryNum].dexNum == 0xFFFF)
{
ClearMonListEntry(MON_LIST_X, i * 2, ignored);
}
else
{
ClearMonListEntry(MON_LIST_X, i * 2, ignored);
if (sPokedexView->pokedexList[entryNum].seen)
{
CreateMonDexNum(entryNum, MON_LIST_X+1, i * 2, ignored);
CreateCaughtBall(sPokedexView->pokedexList[entryNum].owned, MON_LIST_X, i * 2, ignored);
CreateMonName(sPokedexView->pokedexList[entryNum].dexNum, MON_LIST_X + 5, i * 2);
}
else
{
CreateMonDexNum(entryNum, MON_LIST_X+1, i * 2, ignored);
CreateCaughtBall(FALSE, MON_LIST_X, i * 2, ignored);
CreateMonName(0, MON_LIST_X + 5, i * 2);
}
}
entryNum++;
}
break;
case 1: // Up
entryNum = b - 5;
if (entryNum < 0 || entryNum >= NATIONAL_DEX_COUNT || sPokedexView->pokedexList[entryNum].dexNum == 0xFFFF)
{
ClearMonListEntry(MON_LIST_X, sPokedexView->listVOffset * 2, ignored);
}
else
{
ClearMonListEntry(MON_LIST_X, sPokedexView->listVOffset * 2, ignored);
if (sPokedexView->pokedexList[entryNum].seen)
{
CreateMonDexNum(entryNum, MON_LIST_X+1, sPokedexView->listVOffset * 2, ignored);
CreateCaughtBall(sPokedexView->pokedexList[entryNum].owned, MON_LIST_X, sPokedexView->listVOffset * 2, ignored);
CreateMonName(sPokedexView->pokedexList[entryNum].dexNum, MON_LIST_X + 5, sPokedexView->listVOffset * 2);
}
else
{
CreateMonDexNum(entryNum, MON_LIST_X+1, sPokedexView->listVOffset * 2, ignored);
CreateCaughtBall(FALSE, MON_LIST_X, sPokedexView->listVOffset * 2, ignored);
CreateMonName(0, MON_LIST_X + 5, sPokedexView->listVOffset * 2);
}
}
break;
case 2: // Down
entryNum = b + 5;
vOffset = sPokedexView->listVOffset + 10;
if (vOffset >= LIST_SCROLL_STEP)
vOffset -= LIST_SCROLL_STEP;
if (entryNum < 0 || entryNum >= NATIONAL_DEX_COUNT || sPokedexView->pokedexList[entryNum].dexNum == 0xFFFF)
ClearMonListEntry(MON_LIST_X, vOffset * 2, ignored);
else
{
ClearMonListEntry(MON_LIST_X, vOffset * 2, ignored);
if (sPokedexView->pokedexList[entryNum].seen)
{
CreateMonDexNum(entryNum, MON_LIST_X+1, vOffset * 2, ignored);
CreateCaughtBall(sPokedexView->pokedexList[entryNum].owned, MON_LIST_X, vOffset * 2, ignored);
CreateMonName(sPokedexView->pokedexList[entryNum].dexNum, MON_LIST_X + 5, vOffset * 2);
}
else
{
CreateMonDexNum(entryNum, MON_LIST_X+1, vOffset * 2, ignored);
CreateCaughtBall(FALSE, MON_LIST_X, vOffset * 2, ignored);
CreateMonName(0, MON_LIST_X + 5, vOffset * 2);
}
}
break;
}
CopyWindowToVram(0, COPYWIN_GFX);
}
static void CreateMonDexNum(u16 entryNum, u8 left, u8 top, u16 unused)
{
u8 text[5];
u16 dexNum, offset = 0;
dexNum = sPokedexView->pokedexList[entryNum].dexNum;
if (sPokedexView->dexMode == DEX_MODE_HOENN)
dexNum = NationalToHoennOrder(dexNum);
memcpy(text, sText_No0000, ARRAY_COUNT(sText_No0000));
if (NATIONAL_DEX_COUNT > 999 && sPokedexView->dexMode != DEX_MODE_HOENN)
{
text[0] = CHAR_0 + dexNum / 1000;
offset++;
}
text[offset++] = CHAR_0 + (dexNum % 1000) / 100;
text[offset++] = CHAR_0 + ((dexNum % 1000) % 100) / 10;
text[offset++] = CHAR_0 + ((dexNum % 1000) % 100) % 10;
text[offset++] = EOS;
PrintMonDexNumAndName(0, FONT_NARROW, text, left, top);
}
static void CreateCaughtBall(bool16 owned, u8 x, u8 y, u16 unused)
{
if (owned)
BlitBitmapToWindow(0, sCaughtBall_Gfx, x * 6, y * 8, 8, 16);
else
FillWindowPixelRect(0, PIXEL_FILL(0), x * 6, y * 8, 8, 16);
}
static u8 CreateMonName(u16 num, u8 left, u8 top)
{
const u8 *str;
num = NationalPokedexNumToSpecies(num);
if (num)
str = GetSpeciesName(num);
else
str = sText_TenDashes;
PrintMonDexNumAndName_2(0, FONT_NARROW, str, left, top);
return StringLength(str);
}
static void ClearMonListEntry(u8 x, u8 y, u16 unused)
{
FillWindowPixelRect(0, PIXEL_FILL(0), x * 6, y * 8, 0x60, 16);
}
// u16 ignored is passed but never used
static void CreateMonSpritesAtPos(u16 selectedMon, u16 ignored)
{
u8 i;
u16 dexNum;
u8 spriteId;
gPaletteFade.bufferTransferDisabled = TRUE;
for (i = 0; i < MAX_MONS_ON_SCREEN; i++)
sPokedexView->monSpriteIds[i] = 0xFFFF;
sPokedexView->selectedMonSpriteId = 0xFFFF;
// Create top mon sprite
dexNum = GetPokemonSpriteToDisplay(selectedMon - 1);
if (dexNum != 0xFFFF)
{
spriteId = CreatePokedexMonSprite(dexNum, SCROLLING_MON_X, 0x50);
gSprites[spriteId].callback = SpriteCB_PokedexListMonSprite;
gSprites[spriteId].data[5] = -32;
}
// Create mid mon sprite
dexNum = GetPokemonSpriteToDisplay(selectedMon);
if (dexNum != 0xFFFF)
{
spriteId = CreatePokedexMonSprite(dexNum, SCROLLING_MON_X, 0x50);
gSprites[spriteId].callback = SpriteCB_PokedexListMonSprite;
gSprites[spriteId].data[5] = 0;
}
// Create bottom mon sprite
dexNum = GetPokemonSpriteToDisplay(selectedMon + 1);
if (dexNum != 0xFFFF)
{
spriteId = CreatePokedexMonSprite(dexNum, SCROLLING_MON_X, 0x50);
gSprites[spriteId].callback = SpriteCB_PokedexListMonSprite;
gSprites[spriteId].data[5] = 32;
}
CreateMonListEntry(0, selectedMon, ignored);
SetGpuReg(REG_OFFSET_BG2VOFS, sPokedexView->initialVOffset);
sPokedexView->listVOffset = 0;
sPokedexView->listMovingVOffset = 0;
gPaletteFade.bufferTransferDisabled = FALSE;
}
static bool8 UpdateDexListScroll(u8 direction, u8 monMoveIncrement, u8 scrollTimerMax)
{
u16 i;
u8 step;
if (sPokedexView->scrollTimer)
{
sPokedexView->scrollTimer--;
switch (direction)
{
case 1: // Up
for (i = 0; i < MAX_MONS_ON_SCREEN; i++)
{
if (sPokedexView->monSpriteIds[i] != 0xFFFF)
gSprites[sPokedexView->monSpriteIds[i]].data[5] += monMoveIncrement;
}
step = LIST_SCROLL_STEP * (scrollTimerMax - sPokedexView->scrollTimer) / scrollTimerMax;
SetGpuReg(REG_OFFSET_BG2VOFS, sPokedexView->initialVOffset + sPokedexView->listMovingVOffset * LIST_SCROLL_STEP - step);
sPokedexView->pokeBallRotation -= sPokedexView->pokeBallRotationStep;
break;
case 2: // Down
for (i = 0; i < MAX_MONS_ON_SCREEN; i++)
{
if (sPokedexView->monSpriteIds[i] != 0xFFFF)
gSprites[sPokedexView->monSpriteIds[i]].data[5] -= monMoveIncrement;
}
step = LIST_SCROLL_STEP * (scrollTimerMax - sPokedexView->scrollTimer) / scrollTimerMax;
SetGpuReg(REG_OFFSET_BG2VOFS, sPokedexView->initialVOffset + sPokedexView->listMovingVOffset * LIST_SCROLL_STEP + step);
sPokedexView->pokeBallRotation += sPokedexView->pokeBallRotationStep;
break;
}
return FALSE;
}
else
{
SetGpuReg(REG_OFFSET_BG2VOFS, sPokedexView->initialVOffset + sPokedexView->listVOffset * LIST_SCROLL_STEP);
return TRUE;
}
}
static void CreateScrollingPokemonSprite(u8 direction, u16 selectedMon)
{
u16 dexNum;
u8 spriteId;
sPokedexView->listMovingVOffset = sPokedexView->listVOffset;
switch (direction)
{
case 1: // up
dexNum = GetPokemonSpriteToDisplay(selectedMon - 1);
if (dexNum != 0xFFFF)
{
spriteId = CreatePokedexMonSprite(dexNum, SCROLLING_MON_X, 0x50);
gSprites[spriteId].callback = SpriteCB_PokedexListMonSprite;
gSprites[spriteId].data[5] = -64;
}
if (sPokedexView->listVOffset > 0)
sPokedexView->listVOffset--;
else
sPokedexView->listVOffset = LIST_SCROLL_STEP - 1;
break;
case 2: // down
dexNum = GetPokemonSpriteToDisplay(selectedMon + 1);
if (dexNum != 0xFFFF)
{
spriteId = CreatePokedexMonSprite(dexNum, SCROLLING_MON_X, 0x50);
gSprites[spriteId].callback = SpriteCB_PokedexListMonSprite;
gSprites[spriteId].data[5] = 64;
}
if (sPokedexView->listVOffset < LIST_SCROLL_STEP - 1)
sPokedexView->listVOffset++;
else
sPokedexView->listVOffset = 0;
break;
}
}
// u16 ignored is passed but never used
static u16 TryDoPokedexScroll(u16 selectedMon, u16 ignored)
{
u8 scrollTimer;
u8 scrollMonIncrement;
u8 i;
u16 startingPos;
u8 scrollDir = 0;
if (JOY_HELD(DPAD_UP) && (selectedMon > 0))
{
scrollDir = 1;
selectedMon = GetNextPosition(1, selectedMon, 0, sPokedexView->pokemonListCount - 1);
CreateScrollingPokemonSprite(1, selectedMon);
CreateMonListEntry(1, selectedMon, ignored);
sPokedexView->justScrolled = TRUE;
PlaySE(SE_DEX_SCROLL);
}
else if (JOY_HELD(DPAD_DOWN) && (selectedMon < sPokedexView->pokemonListCount - 1))
{
scrollDir = 2;
selectedMon = GetNextPosition(0, selectedMon, 0, sPokedexView->pokemonListCount - 1);
CreateScrollingPokemonSprite(2, selectedMon);
CreateMonListEntry(2, selectedMon, ignored);
sPokedexView->justScrolled = TRUE;
PlaySE(SE_DEX_SCROLL);
}
else if (JOY_NEW(DPAD_LEFT) && (selectedMon > 0))
{
startingPos = selectedMon;
for (i = 0; i < 7; i++)
selectedMon = GetNextPosition(1, selectedMon, 0, sPokedexView->pokemonListCount - 1);
sPokedexView->pokeBallRotation += 16 * (selectedMon - startingPos);
ClearMonSprites();
CreateMonSpritesAtPos(selectedMon, 0xE);
sPokedexView->justScrolled = TRUE;
PlaySE(SE_DEX_PAGE);
}
else if (JOY_NEW(DPAD_RIGHT) && (selectedMon < sPokedexView->pokemonListCount - 1))
{
startingPos = selectedMon;
for (i = 0; i < 7; i++)
selectedMon = GetNextPosition(0, selectedMon, 0, sPokedexView->pokemonListCount - 1);
sPokedexView->pokeBallRotation += 16 * (selectedMon - startingPos);
ClearMonSprites();
CreateMonSpritesAtPos(selectedMon, 0xE);
sPokedexView->justScrolled = TRUE;
PlaySE(SE_DEX_PAGE);
}
if (scrollDir == 0)
{
// Left/right input just snaps up/down, no scrolling
sPokedexView->scrollSpeed = 0;
return selectedMon;
}
scrollMonIncrement = sScrollMonIncrements[sPokedexView->scrollSpeed / 4];
scrollTimer = sScrollTimers[sPokedexView->scrollSpeed / 4];
sPokedexView->scrollTimer = scrollTimer;
sPokedexView->maxScrollTimer = scrollTimer;
sPokedexView->scrollMonIncrement = scrollMonIncrement;
sPokedexView->scrollDirection = scrollDir;
sPokedexView->pokeBallRotationStep = scrollMonIncrement / 2;
UpdateDexListScroll(sPokedexView->scrollDirection, sPokedexView->scrollMonIncrement, sPokedexView->maxScrollTimer);
if (sPokedexView->scrollSpeed < 12)
sPokedexView->scrollSpeed++;
return selectedMon;
}
static void UpdateSelectedMonSpriteId(void)
{
u16 i;
for (i = 0; i < MAX_MONS_ON_SCREEN; i++)
{
u16 spriteId = sPokedexView->monSpriteIds[i];
if (gSprites[spriteId].x2 == 0 && gSprites[spriteId].y2 == 0 && spriteId != 0xFFFF)
sPokedexView->selectedMonSpriteId = spriteId;
}
}
static bool8 TryDoInfoScreenScroll(void)
{
u16 nextPokemon;
u16 selectedPokemon = sPokedexView->selectedPokemon;
if (sPokedexView->sEvoScreenData.fromEvoPage)
return FALSE;
if (JOY_NEW(DPAD_UP) && selectedPokemon)
{
nextPokemon = selectedPokemon;
while (nextPokemon != 0)
{
nextPokemon = GetNextPosition(1, nextPokemon, 0, sPokedexView->pokemonListCount - 1);
if (sPokedexView->pokedexList[nextPokemon].seen)
{
selectedPokemon = nextPokemon;
break;
}
}
if (sPokedexView->selectedPokemon == selectedPokemon)
return FALSE;
else
{
sPokedexView->selectedPokemon = selectedPokemon;
sPokedexView->pokeBallRotation -= 16;
return TRUE;
}
}
else if (JOY_NEW(DPAD_DOWN) && selectedPokemon < sPokedexView->pokemonListCount - 1)
{
nextPokemon = selectedPokemon;
while (nextPokemon < sPokedexView->pokemonListCount - 1)
{
nextPokemon = GetNextPosition(0, nextPokemon, 0, sPokedexView->pokemonListCount - 1);
if (sPokedexView->pokedexList[nextPokemon].seen)
{
selectedPokemon = nextPokemon;
break;
}
}
if (sPokedexView->selectedPokemon == selectedPokemon)
return FALSE;
else
{
sPokedexView->selectedPokemon = selectedPokemon;
sPokedexView->pokeBallRotation += 16;
return TRUE;
}
}
return FALSE;
}
static u8 ClearMonSprites(void)
{
u16 i;
for (i = 0; i < MAX_MONS_ON_SCREEN; i++)
{
if (sPokedexView->monSpriteIds[i] != 0xFFFF)
{
FreeAndDestroyMonPicSprite(sPokedexView->monSpriteIds[i]);
sPokedexView->monSpriteIds[i] = 0xFFFF;
}
}
return FALSE;
}
static u16 GetPokemonSpriteToDisplay(u16 species)
{
if (species >= NATIONAL_DEX_COUNT || sPokedexView->pokedexList[species].dexNum == 0xFFFF)
return 0xFFFF;
else if (sPokedexView->pokedexList[species].seen)
return sPokedexView->pokedexList[species].dexNum;
else
return 0;
}
static u32 CreatePokedexMonSprite(u16 num, s16 x, s16 y)
{
u8 i;
for (i = 0; i < MAX_MONS_ON_SCREEN; i++)
{
if (sPokedexView->monSpriteIds[i] == 0xFFFF)
{
u8 spriteId = CreateMonSpriteFromNationalDexNumberHGSS(num, x, y, i);
gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL;
gSprites[spriteId].oam.priority = 3;
gSprites[spriteId].data[0] = 0;
gSprites[spriteId].data[1] = i;
gSprites[spriteId].data[2] = NationalPokedexNumToSpecies(num);
sPokedexView->monSpriteIds[i] = spriteId;
return spriteId;
}
}
return 0xFFFF;
}
#define sIsDownArrow data[1]
#define LIST_RIGHT_SIDE_TEXT_X 204
#define LIST_RIGHT_SIDE_TEXT_X_OFFSET 13
#define LIST_RIGHT_SIDE_TEXT_Y_OFFSET 13
static void CreateInterfaceSprites(u8 page)
{
u8 spriteId;
u16 digitNum;
bool32 drawNextDigit;
// Scroll arrows
spriteId = CreateSprite(&sScrollArrowSpriteTemplate, 10, 4, 0);
gSprites[spriteId].sIsDownArrow = FALSE;
spriteId = CreateSprite(&sScrollArrowSpriteTemplate, 10, 156, 0);
gSprites[spriteId].sIsDownArrow = TRUE;
gSprites[spriteId].vFlip = TRUE;
CreateSprite(&sScrollBarSpriteTemplate, 6, 20, 0);
if (!IsNationalPokedexEnabled() && page == PAGE_MAIN)
{
// Hoenn text
CreateSprite(&sHoennNationalTextSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X, 40 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET - 6, 1);
// Hoenn seen
CreateSprite(&sSeenOwnTextSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X, 45 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET + 6, 1);
// Hoenn own
spriteId = CreateSprite(&sSeenOwnTextSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X, 55 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET + 7, 1);
StartSpriteAnim(&gSprites[spriteId], 1);
// Hoenn seen value - 100s
drawNextDigit = FALSE;
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X + LIST_RIGHT_SIDE_TEXT_X_OFFSET, 45 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = sPokedexView->seenCount / 100;
StartSpriteAnim(&gSprites[spriteId], digitNum);
if (digitNum != 0)
drawNextDigit = TRUE;
else
gSprites[spriteId].invisible = TRUE;
// Hoenn seen value - 10s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X + LIST_RIGHT_SIDE_TEXT_X_OFFSET + 8, 45 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (sPokedexView->seenCount % 100) / 10;
if (digitNum != 0 || drawNextDigit)
StartSpriteAnim(&gSprites[spriteId], digitNum);
else
gSprites[spriteId].invisible = TRUE;
// Hoenn seen value - 1s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X + LIST_RIGHT_SIDE_TEXT_X_OFFSET + 16, 45 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (sPokedexView->seenCount % 100) % 10;
StartSpriteAnim(&gSprites[spriteId], digitNum);
// Hoenn owned value - 100s
drawNextDigit = FALSE;
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X + LIST_RIGHT_SIDE_TEXT_X_OFFSET, 55 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = sPokedexView->ownCount / 100;
StartSpriteAnim(&gSprites[spriteId], digitNum);
if (digitNum != 0)
drawNextDigit = TRUE;
else
gSprites[spriteId].invisible = TRUE;
// Hoenn owned value - 10s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X + LIST_RIGHT_SIDE_TEXT_X_OFFSET + 8, 55 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (sPokedexView->ownCount % 100) / 10;
if (digitNum != 0 || drawNextDigit)
StartSpriteAnim(&gSprites[spriteId], digitNum);
else
gSprites[spriteId].invisible = TRUE;
// Hoenn owned value - 1s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X + LIST_RIGHT_SIDE_TEXT_X_OFFSET + 16, 55 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (sPokedexView->ownCount % 100) % 10;
StartSpriteAnim(&gSprites[spriteId], digitNum);
}
else if (page == PAGE_MAIN)
{
u16 seenOwnedCount;
u8 counterXDist = 6;
u8 counterX1s = LIST_RIGHT_SIDE_TEXT_X + LIST_RIGHT_SIDE_TEXT_X_OFFSET + 16 - (sPokedexView->seenCount > 999 ? 0 : 1);
u8 counterX10s = counterX1s - counterXDist;
u8 counterX100s = counterX10s - counterXDist;
u8 counterX1000s = counterX100s - counterXDist;
// Hoenn text
CreateSprite(&sHoennNationalTextSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X, 40 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET - 6, 1);
// Hoenn seen
CreateSprite(&sSeenOwnTextSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X, 45 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET + 6, 1);
// Hoenn own
spriteId = CreateSprite(&sSeenOwnTextSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X, 55 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET + 7, 1);
StartSpriteAnim(&gSprites[spriteId], 1);
// National text
spriteId = CreateSprite(&sHoennNationalTextSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X, 73 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET - 6, 1);
StartSpriteAnim(&gSprites[spriteId], 1);
// National seen
CreateSprite(&sSeenOwnTextSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X, 78 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET + 6, 1);
// National own
spriteId = CreateSprite(&sSeenOwnTextSpriteTemplate, LIST_RIGHT_SIDE_TEXT_X, 88 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET + 6, 1);
StartSpriteAnim(&gSprites[spriteId], 1);
// Hoenn seen value - 100s
seenOwnedCount = GetHoennPokedexCount(FLAG_GET_SEEN);
drawNextDigit = FALSE;
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX100s, 45 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = seenOwnedCount / 100;
StartSpriteAnim(&gSprites[spriteId], digitNum);
if (digitNum != 0)
drawNextDigit = TRUE;
else
gSprites[spriteId].invisible = TRUE;
// Hoenn seen value - 10s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX10s, 45 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (seenOwnedCount % 100) / 10;
if (digitNum != 0 || drawNextDigit)
StartSpriteAnim(&gSprites[spriteId], digitNum);
else
gSprites[spriteId].invisible = TRUE;
// Hoenn seen value - 1s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX1s, 45 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (seenOwnedCount % 100) % 10;
StartSpriteAnim(&gSprites[spriteId], digitNum);
seenOwnedCount = GetHoennPokedexCount(FLAG_GET_CAUGHT);
// Hoenn owned value - 100s
drawNextDigit = FALSE;
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX100s, 55 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = seenOwnedCount / 100;
StartSpriteAnim(&gSprites[spriteId], digitNum);
if (digitNum != 0)
drawNextDigit = TRUE;
else
gSprites[spriteId].invisible = TRUE;
// Hoenn owned value - 10s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX10s, 55 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (seenOwnedCount % 100) / 10;
if (digitNum != 0 || drawNextDigit)
StartSpriteAnim(&gSprites[spriteId], digitNum);
else
gSprites[spriteId].invisible = TRUE;
// Hoenn owned value - 1s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX1s, 55 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (seenOwnedCount % 100) % 10;
StartSpriteAnim(&gSprites[spriteId], digitNum);
//****************************
// National seen value - 1000s
drawNextDigit = FALSE;
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX1000s, 78 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = sPokedexView->seenCount / 1000;
StartSpriteAnim(&gSprites[spriteId], digitNum);
if (digitNum != 0)
drawNextDigit = TRUE;
else
gSprites[spriteId].invisible = TRUE;
// National seen value - 100s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX100s, 78 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (sPokedexView->seenCount % 1000) / 100;
if (digitNum != 0 || drawNextDigit)
{
drawNextDigit = TRUE;
StartSpriteAnim(&gSprites[spriteId], digitNum);
}
else
gSprites[spriteId].invisible = TRUE;
// National seen value - 10s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX10s, 78 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = ((sPokedexView->seenCount % 1000) % 100) / 10;
if (digitNum != 0 || drawNextDigit)
StartSpriteAnim(&gSprites[spriteId], digitNum);
else
gSprites[spriteId].invisible = TRUE;
// National seen value - 1s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX1s, 78 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = ((sPokedexView->seenCount % 1000) % 100) % 10;
StartSpriteAnim(&gSprites[spriteId], digitNum);
// National owned value - 1000s
drawNextDigit = FALSE;
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX1000s, 88 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = sPokedexView->ownCount / 1000;
StartSpriteAnim(&gSprites[spriteId], digitNum);
if (digitNum != 0)
drawNextDigit = TRUE;
else
gSprites[spriteId].invisible = TRUE;
// National owned value - 100s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX100s, 88 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = (sPokedexView->ownCount % 1000) / 100;
if (digitNum != 0 || drawNextDigit)
{
drawNextDigit = TRUE;
StartSpriteAnim(&gSprites[spriteId], digitNum);
}
else
gSprites[spriteId].invisible = TRUE;
// National owned value - 10s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX10s, 88 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = ((sPokedexView->ownCount % 1000) % 100) / 10;
if (digitNum != 0 || drawNextDigit)
StartSpriteAnim(&gSprites[spriteId], digitNum);
else
gSprites[spriteId].invisible = TRUE;
// National owned value - 1s
spriteId = CreateSprite(&sNationalDexSeenOwnNumberSpriteTemplate, counterX1s, 88 - LIST_RIGHT_SIDE_TEXT_Y_OFFSET, 1);
digitNum = ((sPokedexView->ownCount % 1000) % 100) % 10;
StartSpriteAnim(&gSprites[spriteId], digitNum);
}
if (page == PAGE_MAIN)
{
spriteId = CreateSprite(&sDexListStartMenuCursorSpriteTemplate, 136, 96, 1);
gSprites[spriteId].invisible = TRUE;
}
else // PAGE_SEARCH_RESULTS
{
spriteId = CreateSprite(&sDexListStartMenuCursorSpriteTemplate, 136, 80, 1);
gSprites[spriteId].invisible = TRUE;
}
}
static void SpriteCB_EndMoveMonForInfoScreen(struct Sprite *sprite)
{
// Once mon is done moving there's nothing left to do
}
static void SpriteCB_SeenOwnInfo(struct Sprite *sprite)
{
if (sPokedexView->currentPage != PAGE_MAIN && sPokedexView->currentPage != PAGE_SEARCH_RESULTS)
DestroySprite(sprite);
}
static void SpriteCB_MoveMonForInfoScreen(struct Sprite *sprite)
{
sprite->oam.priority = 0;
sprite->oam.affineMode = ST_OAM_AFFINE_OFF;
sprite->x2 = 0;
sprite->y2 = 0;
if (sprite->x != MON_PAGE_X || sprite->y != MON_PAGE_Y)
{
if (sprite->x > 48)
sprite->x -= 4;
if (sprite->x < 48)
sprite->x = 48;
if (sprite->y > 56)
sprite->y -= 4;
if (sprite->y < 56)
sprite->y = 56;
}
else
{
sprite->callback = SpriteCB_EndMoveMonForInfoScreen;
}
}
static void SpriteCB_PokedexListMonSprite(struct Sprite *sprite)
{
u8 monId = sprite->data[1];
if (sPokedexView->currentPage != PAGE_MAIN && sPokedexView->currentPage != PAGE_SEARCH_RESULTS)
{
FreeAndDestroyMonPicSprite(sPokedexView->monSpriteIds[monId]);
sPokedexView->monSpriteIds[monId] = 0xFFFF;
}
else
{
u32 var;
sprite->y2 = gSineTable[(u8)sprite->data[5]] * 76 / 256;
var = SAFE_DIV(0x10000, gSineTable[sprite->data[5] + 64]);
if (var > 0xFFFF)
var = 0xFFFF;
SetOamMatrix(sprite->data[1] + 1, 0x100, 0, 0, var);
sprite->oam.matrixNum = monId + 1;
if (sprite->data[5] > -64 && sprite->data[5] < 64)
{
sprite->invisible = FALSE;
sprite->data[0] = 1;
}
else
{
sprite->invisible = TRUE;
}
if ((sprite->data[5] <= -64 || sprite->data[5] >= 64) && sprite->data[0] != 0)
{
FreeAndDestroyMonPicSprite(sPokedexView->monSpriteIds[monId]);
sPokedexView->monSpriteIds[monId] = 0xFFFF;
}
}
}
static void SpriteCB_Scrollbar(struct Sprite *sprite)
{
if (sPokedexView->currentPage != PAGE_MAIN && sPokedexView->currentPage != PAGE_SEARCH_RESULTS)
DestroySprite(sprite);
else
sprite->y2 = sPokedexView->selectedPokemon * 120 / (sPokedexView->pokemonListCount - 1);
}
static void SpriteCB_ScrollArrow(struct Sprite *sprite)
{
if (sPokedexView->currentPage != PAGE_MAIN && sPokedexView->currentPage != PAGE_SEARCH_RESULTS)
{
DestroySprite(sprite);
}
else
{
u8 r0;
if (sprite->sIsDownArrow)
{
if (sPokedexView->selectedPokemon == sPokedexView->pokemonListCount - 1)
sprite->invisible = TRUE;
else
sprite->invisible = FALSE;
r0 = sprite->data[2];
}
else
{
if (sPokedexView->selectedPokemon == 0)
sprite->invisible = TRUE;
else
sprite->invisible = FALSE;
r0 = sprite->data[2] - 128;
}
sprite->y2 = gSineTable[r0] / 64;
sprite->data[2] = sprite->data[2] + 8;
if (sPokedexView->menuIsOpen == FALSE && sPokedexView->menuY == 0 && sprite->invisible == FALSE)
sprite->invisible = FALSE;
else
sprite->invisible = TRUE;
}
}
static void SpriteCB_DexListInterfaceText(struct Sprite *sprite)
{
if (sPokedexView->currentPage != PAGE_MAIN && sPokedexView->currentPage != PAGE_SEARCH_RESULTS)
DestroySprite(sprite);
}
static void SpriteCB_RotatingPokeBall(struct Sprite *sprite)
{
if (sPokedexView->currentPage != PAGE_MAIN && sPokedexView->currentPage != PAGE_SEARCH_RESULTS)
{
DestroySprite(sprite);
}
else
{
u8 val;
s16 r3;
s16 r0;
val = sPokedexView->pokeBallRotation + sprite->data[1];
r3 = gSineTable[val];
r0 = gSineTable[val + 64];
SetOamMatrix(sprite->data[0], r0, r3, -r3, r0);
val = sPokedexView->pokeBallRotation + (sprite->data[1] + 64);
r3 = gSineTable[val];
r0 = gSineTable[val + 64];
sprite->x2 = r0 * 40 / 256;
sprite->y2 = r3 * 40 / 256;
}
}
static void SpriteCB_DexListStartMenuCursor(struct Sprite *sprite)
{
if (sPokedexView->currentPage != PAGE_MAIN && sPokedexView->currentPage != PAGE_SEARCH_RESULTS)
{
DestroySprite(sprite);
}
else
{
u16 r1 = sPokedexView->currentPage == PAGE_MAIN ? 80 : 96;
if (sPokedexView->menuIsOpen && sPokedexView->menuY == r1)
{
sprite->invisible = FALSE;
sprite->y2 = sPokedexView->menuCursorPos * 16;
sprite->x2 = gSineTable[(u8)sprite->data[2]] / 64;
sprite->data[2] += 8;
}
else
{
sprite->invisible = TRUE;
}
}
}
//************************************
//* *
//* STATS BARS *
//* *
//************************************
//Stat bars on main screen, code by DizzyEgg, idea by Jaizu
#define PIXEL_COORDS_TO_OFFSET(x, y)( \
/*Add tiles by X*/ \
((y / 8) * 32 * 8) \
/*Add tiles by X*/ \
+ ((x / 8) * 32) \
/*Add pixels by Y*/ \
+ ((((y) - ((y / 8) * 8))) * 4) \
/*Add pixels by X*/ \
+ ((((x) - ((x / 8) * 8)) / 2)))
static inline void WritePixel(u8 *dst, u32 x, u32 y, u32 value)
{
if (x & 1)
{
dst[PIXEL_COORDS_TO_OFFSET(x, y)] &= ~0xF0;
dst[PIXEL_COORDS_TO_OFFSET(x, y)] |= (value << 4);
}
else
{
dst[PIXEL_COORDS_TO_OFFSET(x, y)] &= ~0xF;
dst[PIXEL_COORDS_TO_OFFSET(x, y)] |= (value);
}
}
#define STAT_BAR_X_OFFSET 10
static void CreateStatBar(u8 *dst, u32 y, u32 width)
{
u32 i, color;
switch (width)
{
case 0 ... 5:
color = COLOR_WORST;
break;
case 6 ... 15:
color = COLOR_BAD;
break;
case 16 ... 25:
color = COLOR_AVERAGE;
break;
case 26 ... 31:
color = COLOR_GOOD;
break;
case 32 ... 37:
color = COLOR_VERY_GOOD;
break;
default:
color = COLOR_BEST;
break;
}
// white pixes left side
WritePixel(dst, STAT_BAR_X_OFFSET, y + 0, COLOR_ID_BAR_WHITE);
WritePixel(dst, STAT_BAR_X_OFFSET, y + 1, COLOR_ID_BAR_WHITE);
WritePixel(dst, STAT_BAR_X_OFFSET, y + 2, COLOR_ID_BAR_WHITE);
WritePixel(dst, STAT_BAR_X_OFFSET, y + 3, COLOR_ID_BAR_WHITE);
WritePixel(dst, STAT_BAR_X_OFFSET, y + 4, COLOR_ID_BAR_WHITE);
// white pixels right side
WritePixel(dst, STAT_BAR_X_OFFSET + width - 1, y + 0, COLOR_ID_BAR_WHITE);
WritePixel(dst, STAT_BAR_X_OFFSET + width - 1, y + 1, COLOR_ID_BAR_WHITE);
WritePixel(dst, STAT_BAR_X_OFFSET + width - 1, y + 2, COLOR_ID_BAR_WHITE);
WritePixel(dst, STAT_BAR_X_OFFSET + width - 1, y + 3, COLOR_ID_BAR_WHITE);
WritePixel(dst, STAT_BAR_X_OFFSET + width - 1, y + 4, COLOR_ID_BAR_WHITE);
// Fill
for (i = 1; i < width - 1; i++)
{
WritePixel(dst, STAT_BAR_X_OFFSET + i, y + 0, COLOR_ID_BAR_WHITE);
WritePixel(dst, STAT_BAR_X_OFFSET + i, y + 1, COLOR_ID_FILL_SHADOW + color * 2);
WritePixel(dst, STAT_BAR_X_OFFSET + i, y + 2, COLOR_ID_FILL + color * 2);
WritePixel(dst, STAT_BAR_X_OFFSET + i, y + 3, COLOR_ID_FILL + color * 2);
WritePixel(dst, STAT_BAR_X_OFFSET + i, y + 4, COLOR_ID_BAR_WHITE);
}
}
static const u8 sBaseStatOffsets[] =
{
offsetof(struct SpeciesInfo, baseHP),
offsetof(struct SpeciesInfo, baseAttack),
offsetof(struct SpeciesInfo, baseDefense),
offsetof(struct SpeciesInfo, baseSpAttack),
offsetof(struct SpeciesInfo, baseSpDefense),
offsetof(struct SpeciesInfo, baseSpeed),
};
static void TryDestroyStatBars(void)
{
if (sPokedexView->statBarsSpriteId != 0xFF)
{
FreeSpriteTilesByTag(TAG_STAT_BAR);
//FreeSpriteOamMatrix(&gSprites[sPokedexView->statBarsSpriteId]);
DestroySprite(&gSprites[sPokedexView->statBarsSpriteId]);
sPokedexView->statBarsSpriteId = 0xFF;
}
}
static void TryDestroyStatBarsBg(void)
{
if (sPokedexView->statBarsBgSpriteId != 0xFF)
{
FreeSpriteTilesByTag(TAG_STAT_BAR_BG);
//FreeSpriteOamMatrix(&gSprites[sPokedexView->statBarsBgSpriteId]);
DestroySprite(&gSprites[sPokedexView->statBarsBgSpriteId]);
sPokedexView->statBarsBgSpriteId = 0xFF;
}
}
static void CreateStatBars(struct PokedexListItem *dexMon)
{
u8 offset_x = 184; //Moves the complete stat box left/right
u8 offset_y = 16; //Moves the complete stat box up/down
TryDestroyStatBars();
sPokedexView->justScrolled = FALSE;
if (dexMon->owned) // Show filed bars
{
u8 i;
u32 width, statValue;
u8 *gfx = Alloc(64 * 64);
static const u8 sBarsYOffset[] = {3, 13, 23, 33, 43, 53};
struct SpriteSheet sheet = {gfx, 64 * 64, TAG_STAT_BAR};
u32 species = NationalPokedexNumToSpecies(dexMon->dexNum);
memcpy(gfx, sStatBarsGfx, sizeof(sStatBarsGfx));
for (i = 0; i < NUM_STATS; i++)
{
statValue = *((u8*)(&gSpeciesInfo[species]) + sBaseStatOffsets[i]);
if (statValue <= 100)
{
width = statValue / 3;
if (width >= 33)
width -= 1;
}
else
width = (100 / 3) + ((statValue - 100) / 14);
if (width > 39) // Max pixels
width = 39;
if (width < 3)
width = 3;
CreateStatBar(gfx, sBarsYOffset[i], width);
}
LoadSpriteSheet(&sheet);
Free(gfx);
}
else if (dexMon->seen) // Just HP/ATK/DEF
{
static const struct SpriteSheet sheet = {sStatBarsGfx, 64 * 64, TAG_STAT_BAR};
LoadSpriteSheet(&sheet);
}
else // neither seen nor owned
{
return;
}
sPokedexView->statBarsSpriteId = CreateSprite(&sStatBarSpriteTemplate, 36+offset_x, 107+offset_y, 10);
}
static void CreateStatBarsBg(void) //stat bars background text
{
static const struct SpriteSheet sheetStatBarsBg = {sStatBarsGfx, 64 * 64, TAG_STAT_BAR_BG};
u8 offset_x = 184; //Moves the complete stat box left/right
u8 offset_y = 16; //Moves the complete stat box up/down
TryDestroyStatBarsBg();
LoadSpriteSheet(&sheetStatBarsBg);
sPokedexView->statBarsBgSpriteId = CreateSprite(&sStatBarBgSpriteTemplate, 36+offset_x, 107+offset_y, 0);
}
// Hack to destroy sprites when a pokemon data is being loaded in
static bool32 IsMonInfoBeingLoaded(void)
{
return (gSprites[sPokedexView->selectedMonSpriteId].callback == SpriteCB_MoveMonForInfoScreen);
}
static void SpriteCB_StatBars(struct Sprite *sprite)
{
if (IsMonInfoBeingLoaded())
sprite->invisible = TRUE;
if (sPokedexView->currentPage != PAGE_MAIN && sPokedexView->currentPage != PAGE_SEARCH_RESULTS)
{
FreeSpriteTilesByTag(TAG_STAT_BAR);
FreeSpriteOamMatrix(&gSprites[sPokedexView->statBarsSpriteId]);
DestroySprite(&gSprites[sPokedexView->statBarsSpriteId]);
sPokedexView->statBarsSpriteId = 0xFF;
}
}
static void SpriteCB_StatBarsBg(struct Sprite *sprite)
{
if (IsMonInfoBeingLoaded())
sprite->invisible = TRUE;
if (sPokedexView->currentPage != PAGE_MAIN && sPokedexView->currentPage != PAGE_SEARCH_RESULTS)
{
FreeSpriteTilesByTag(TAG_STAT_BAR_BG);
FreeSpriteOamMatrix(&gSprites[sPokedexView->statBarsBgSpriteId]);
DestroySprite(&gSprites[sPokedexView->statBarsBgSpriteId]);
sPokedexView->statBarsBgSpriteId = 0xFF;
}
}
//************************************
//* *
//* Info screen *
//* *
//************************************
#define tScrolling data[0]
#define tMonSpriteDone data[1]
#define tBgLoaded data[2]
#define tSkipCry data[3]
#define tMonSpriteId data[4]
#define tTrainerSpriteId data[5]
static u8 LoadInfoScreen(struct PokedexListItem *item, u8 monSpriteId)
{
u8 taskId;
sPokedexListItem = item;
taskId = CreateTask(Task_LoadInfoScreen, 0);
gTasks[taskId].tScrolling = FALSE;
gTasks[taskId].tMonSpriteDone = TRUE; // Already has sprite from list view
gTasks[taskId].tBgLoaded = FALSE;
gTasks[taskId].tSkipCry = FALSE;
gTasks[taskId].tMonSpriteId = monSpriteId;
gTasks[taskId].tTrainerSpriteId = SPRITE_NONE;
ResetBgsAndClearDma3BusyFlags(0);
InitBgsFromTemplates(0, sInfoScreen_BgTemplate, ARRAY_COUNT(sInfoScreen_BgTemplate));
SetBgTilemapBuffer(3, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(2, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(1, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(0, AllocZeroed(BG_SCREEN_SIZE));
InitWindows(sInfoScreen_WindowTemplates);
DeactivateAllTextPrinters();
return taskId;
}
static bool8 IsInfoScreenScrolling(u8 taskId)
{
if (!gTasks[taskId].tScrolling && gTasks[taskId].func == Task_HandleInfoScreenInput)
return FALSE;
else
return TRUE;
}
static u8 StartInfoScreenScroll(struct PokedexListItem *item, u8 taskId)
{
sPokedexListItem = item;
gTasks[taskId].tScrolling = TRUE;
gTasks[taskId].tMonSpriteDone = FALSE;
gTasks[taskId].tBgLoaded = FALSE;
gTasks[taskId].tSkipCry = FALSE;
return taskId;
}
static void Task_LoadInfoScreen(u8 taskId)
{
switch (gMain.state)
{
case 0:
default:
if (!gPaletteFade.active)
{
u16 r2;
sPokedexView->currentPage = PAGE_INFO;
gPokedexVBlankCB = gMain.vblankCallback;
SetVBlankCallback(NULL);
r2 = 0;
if (gTasks[taskId].tMonSpriteDone)
r2 += DISPCNT_OBJ_ON;
if (gTasks[taskId].tBgLoaded)
r2 |= DISPCNT_BG1_ON;
ResetOtherVideoRegisters(r2);
gMain.state = 1;
}
break;
case 1:
LoadTilesetTilemapHGSS(INFO_SCREEN);
FillWindowPixelBuffer(WIN_INFO, PIXEL_FILL(0));
PutWindowTilemap(WIN_INFO);
PutWindowTilemap(WIN_FOOTPRINT);
DrawFootprint(WIN_FOOTPRINT, NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum));
CopyWindowToVram(WIN_FOOTPRINT, COPYWIN_GFX);
gMain.state++;
break;
case 2:
LoadScreenSelectBarMain(0xD);
LoadPokedexBgPalette(sPokedexView->isSearchResults);
gMain.state++;
break;
case 3:
sPokedexView->typeIconSpriteIds[0] = 0xFF;
sPokedexView->typeIconSpriteIds[1] = 0xFF;
CreateTypeIconSprites();
gMain.state++;
break;
case 4:
PrintMonInfo(sPokedexListItem->dexNum, sPokedexView->dexMode == DEX_MODE_HOENN ? FALSE : TRUE, sPokedexListItem->owned, 0);
if (!sPokedexListItem->owned)
LoadPalette(gPlttBufferUnfaded + 1, BG_PLTT_ID(3) + 1, PLTT_SIZEOF(16 - 1));
CopyWindowToVram(WIN_INFO, COPYWIN_FULL);
CopyBgTilemapBufferToVram(1);
CopyBgTilemapBufferToVram(2);
CopyBgTilemapBufferToVram(3);
gMain.state++;
break;
case 5:
if (!gTasks[taskId].tMonSpriteDone)
{
gTasks[taskId].tMonSpriteId = (u16)CreateMonSpriteFromNationalDexNumberHGSS(sPokedexListItem->dexNum, MON_PAGE_X, MON_PAGE_Y, 0);
gSprites[gTasks[taskId].tMonSpriteId].oam.priority = 0;
}
gMain.state++;
break;
case 6:
{
u32 preservedPalettes = 0;
if (gTasks[taskId].tBgLoaded)
preservedPalettes = 0x14; // each bit represents a palette index
if (gTasks[taskId].tMonSpriteDone)
preservedPalettes |= (1 << (gSprites[gTasks[taskId].tMonSpriteId].oam.paletteNum + 16));
BeginNormalPaletteFade(~preservedPalettes, 0, 16, 0, RGB_BLACK);
SetVBlankCallback(gPokedexVBlankCB);
gMain.state++;
break;
}
case 7:
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
HideBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 8:
if (!gPaletteFade.active)
{
gMain.state++;
}
break;
case 9:
gMain.state++;
break;
case 10:
gTasks[taskId].tScrolling = FALSE;
gTasks[taskId].tMonSpriteDone = FALSE; // Reload next time screen comes up
gTasks[taskId].tBgLoaded = TRUE;
gTasks[taskId].tSkipCry = TRUE;
gTasks[taskId].func = Task_HandleInfoScreenInput;
gMain.state = 0;
break;
}
}
static void FreeInfoScreenWindowAndBgBuffers(void)
{
void *tilemapBuffer;
FreeAllWindowBuffers();
tilemapBuffer = GetBgTilemapBuffer(0);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(1);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(2);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(3);
if (tilemapBuffer)
Free(tilemapBuffer);
}
static void Task_HandleInfoScreenInput(u8 taskId)
{
if (gTasks[taskId].tScrolling)
{
// Scroll up/down
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
gTasks[taskId].func = Task_LoadInfoScreenWaitForFade;
PlaySE(SE_DEX_SCROLL);
return;
}
if (JOY_NEW(B_BUTTON))
{
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
gTasks[taskId].func = Task_ExitInfoScreen;
PlaySE(SE_PC_OFF);
return;
}
if ((JOY_NEW(DPAD_RIGHT) || (JOY_NEW(R_BUTTON) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_LR)))
{
sPokedexView->selectedScreen = AREA_SCREEN;
BeginNormalPaletteFade(0xFFFFFFEB, 0, 0, 0x10, RGB_BLACK);
sPokedexView->screenSwitchState = 1;
gTasks[taskId].func = Task_SwitchScreensFromInfoScreen;
PlaySE(SE_PIN);
}
}
static void Task_SwitchScreensFromInfoScreen(u8 taskId)
{
if (!gPaletteFade.active)
{
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
switch (sPokedexView->screenSwitchState)
{
case 1:
default:
gTasks[taskId].func = Task_LoadAreaScreen;
break;
case 2:
gTasks[taskId].func = Task_LoadCryScreen;
break;
case 3:
gTasks[taskId].func = Task_LoadSizeScreen;
break;
}
}
}
static void Task_LoadInfoScreenWaitForFade(u8 taskId)
{
if (!gPaletteFade.active)
{
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
gTasks[taskId].func = Task_LoadInfoScreen;
}
}
static void Task_ExitInfoScreen(u8 taskId)
{
if (!gPaletteFade.active)
{
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
FreeInfoScreenWindowAndBgBuffers();
DestroyTask(taskId);
}
}
#undef tMonSpriteId
//************************************
//* *
//* Area screen *
//* *
//************************************
static void Task_LoadAreaScreen(u8 taskId)
{
switch (gMain.state)
{
case 0:
default:
if (!gPaletteFade.active)
{
sPokedexView->currentPage = PAGE_AREA;
gPokedexVBlankCB = gMain.vblankCallback;
SetVBlankCallback(NULL);
ResetOtherVideoRegisters(DISPCNT_BG1_ON);
sPokedexView->selectedScreen = AREA_SCREEN;
gMain.state = 1;
}
break;
case 1:
LoadPokedexBgPalette(sPokedexView->isSearchResults);
SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(13) | BGCNT_16COLOR | BGCNT_TXT256x256);
gMain.state++;
break;
case 2:
ShowPokedexAreaScreen(NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum), &sPokedexView->screenSwitchState);
SetVBlankCallback(gPokedexVBlankCB);
sPokedexView->screenSwitchState = 0;
gMain.state = 0;
gTasks[taskId].func = Task_WaitForAreaScreenInput;
break;
}
}
static void Task_WaitForAreaScreenInput(u8 taskId)
{
// See Task_HandlePokedexAreaScreenInput() in pokedex_area_screen.c
if (sPokedexView->screenSwitchState != 0)
gTasks[taskId].func = Task_SwitchScreensFromAreaScreen;
}
static void Task_SwitchScreensFromAreaScreen(u8 taskId)
{
if (!gPaletteFade.active)
{
switch (sPokedexView->screenSwitchState)
{
case 1:
default:
gTasks[taskId].func = Task_LoadInfoScreen;
break;
case 2:
if (!sPokedexListItem->owned)
PlaySE(SE_FAILURE);
else
gTasks[taskId].func = Task_LoadStatsScreen;
break;
}
}
}
//************************************
//* *
//* Select bar *
//* *
//************************************
static void LoadScreenSelectBarMain(u16 unused)
{
CopyToBgTilemapBuffer(1, sPokedexPlusHGSS_ScreenSelectBarSubmenu_Tilemap_Clear, 0, 0);
CopyBgTilemapBufferToVram(1);
}
static void UNUSED HighlightScreenSelectBarItem(u8 selectedScreen, u16 unused)
{
u8 i;
u8 j;
u16 *ptr = GetBgTilemapBuffer(1);
for (i = 0; i < SCREEN_COUNT; i++)
{
u8 row = (i * 7) + 1;
u16 newPalette;
do
{
newPalette = 0x4000;
if (i == selectedScreen)
newPalette = 0x2000;
} while (0);
for (j = 0; j < 7; j++)
{
ptr[row + j] = (ptr[row + j] % 0x1000) | newPalette;
ptr[row + j + 0x20] = (ptr[row + j + 0x20] % 0x1000) | newPalette;
}
}
CopyBgTilemapBufferToVram(1);
}
//************************************
//* *
//* CAUGHT MON *
//* *
//************************************
#define tState data[0]
#define tSpecies data[1]
#define tPalTimer data[2]
#define tMonSpriteId data[3]
#define tOtIdLo data[12]
#define tOtIdHi data[13]
#define tPersonalityLo data[14]
#define tPersonalityHi data[15]
void Task_DisplayCaughtMonDexPageHGSS(u8 taskId)
{
u8 spriteId;
u16 species;
u16 dexNum;
if (!POKEDEX_PLUS_HGSS) return; // prevents the compiler from emitting static .rodata
// if the feature is disabled
species = gTasks[taskId].tSpecies;
dexNum = SpeciesToNationalPokedexNum(species);
switch (gTasks[taskId].tState)
{
case 0:
default:
if (!gPaletteFade.active)
{
gPokedexVBlankCB = gMain.vblankCallback;
SetVBlankCallback(NULL);
ResetOtherVideoRegisters(DISPCNT_BG0_ON);
ResetBgsAndClearDma3BusyFlags(0);
InitBgsFromTemplates(0, sNewEntryInfoScreen_BgTemplate, ARRAY_COUNT(sNewEntryInfoScreen_BgTemplate));
SetBgTilemapBuffer(3, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(2, AllocZeroed(BG_SCREEN_SIZE));
InitWindows(sNewEntryInfoScreen_WindowTemplates);
DeactivateAllTextPrinters();
gTasks[taskId].tState = 1;
}
break;
case 1:
sPokedexView = AllocZeroed(sizeof(struct PokedexView)); //for type icons
ResetPokedexView(sPokedexView);
if (GetSpeciesFormTable(species) != NULL)
sPokedexView->formSpecies = species;
else
sPokedexView->formSpecies = 0;
LoadTilesetTilemapHGSS(INFO_SCREEN);
FillWindowPixelBuffer(WIN_INFO, PIXEL_FILL(0));
PutWindowTilemap(WIN_INFO);
PutWindowTilemap(WIN_FOOTPRINT);
DrawFootprint(WIN_FOOTPRINT, species);
CopyWindowToVram(WIN_FOOTPRINT, COPYWIN_GFX);
ResetPaletteFade();
LoadPokedexBgPalette(FALSE);
gTasks[taskId].tState++;
break;
case 2:
sPokedexView->typeIconSpriteIds[0] = 0xFF;
sPokedexView->typeIconSpriteIds[1] = 0xFF;
CreateTypeIconSprites();
gTasks[taskId].tState++;
break;
case 3:
PrintMonInfo(dexNum, IsNationalPokedexEnabled(), 1, 1);
CopyWindowToVram(WIN_INFO, COPYWIN_FULL);
CopyBgTilemapBufferToVram(2);
CopyBgTilemapBufferToVram(3);
gTasks[taskId].tState++;
break;
case 4:
spriteId = CreateMonSpriteFromNationalDexNumberHGSS(dexNum, MON_PAGE_X, MON_PAGE_Y, 0);
gSprites[spriteId].oam.priority = 0;
BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK);
SetVBlankCallback(gPokedexVBlankCB);
gTasks[taskId].tMonSpriteId = spriteId;
gTasks[taskId].tState++;
break;
case 5:
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
ShowBg(2);
ShowBg(3);
gTasks[taskId].tState++;
break;
case 6:
if (!gPaletteFade.active)
{
PlayCry_Normal(species, 0);
gTasks[taskId].tPalTimer = 0;
gTasks[taskId].func = Task_HandleCaughtMonPageInput;
}
break;
}
}
static void Task_HandleCaughtMonPageInput(u8 taskId)
{
if (JOY_NEW(A_BUTTON | B_BUTTON))
{
BeginNormalPaletteFade(PALETTES_BG, 0, 0, 16, RGB_BLACK);
SetSpriteInvisibility(0, TRUE);
SetSpriteInvisibility(1, TRUE);
gSprites[gTasks[taskId].tMonSpriteId].callback = SpriteCB_SlideCaughtMonToCenter;
gTasks[taskId].func = Task_ExitCaughtMonPage;
}
// Flicker caught screen color
else if (++gTasks[taskId].tPalTimer & 16)
{
if (!HGSS_DARK_MODE)
LoadPalette(sPokedexPlusHGSS_Default_Pal + 1, BG_PLTT_ID(3) + 1, PLTT_SIZEOF(7));
else
LoadPalette(sPokedexPlusHGSS_Default_dark_Pal + 1, BG_PLTT_ID(3) + 1, PLTT_SIZEOF(7));
}
else
{
if (!HGSS_DARK_MODE)
LoadPalette(sPokedexPlusHGSS_Default_Pal + 1, BG_PLTT_ID(3) + 1, PLTT_SIZEOF(7));
else
LoadPalette(sPokedexPlusHGSS_Default_dark_Pal + 1, BG_PLTT_ID(3) + 1, PLTT_SIZEOF(7));
}
}
static void Task_ExitCaughtMonPage(u8 taskId)
{
if (!gPaletteFade.active)
{
u16 species;
u32 otId;
u32 personality;
u8 paletteNum;
const u32 *lzPaletteData;
void *buffer;
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
FreeAllWindowBuffers();
buffer = GetBgTilemapBuffer(2);
if (buffer)
Free(buffer);
buffer = GetBgTilemapBuffer(3);
if (buffer)
Free(buffer);
species = gTasks[taskId].tSpecies;
otId = ((u16)gTasks[taskId].tOtIdHi << 16) | (u16)gTasks[taskId].tOtIdLo;
personality = ((u16)gTasks[taskId].tPersonalityHi << 16) | (u16)gTasks[taskId].tPersonalityLo;
paletteNum = gSprites[gTasks[taskId].tMonSpriteId].oam.paletteNum;
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(species, otId, personality);
LoadCompressedPalette(lzPaletteData, OBJ_PLTT_ID(paletteNum), PLTT_SIZE_4BPP);
DestroyTask(taskId);
}
}
static void SpriteCB_SlideCaughtMonToCenter(struct Sprite *sprite)
{
if (sprite->x < 0x78)
sprite->x += 2;
if (sprite->x > 0x78)
sprite->x -= 2;
if (sprite->y < 0x50)
sprite->y += 1;
if (sprite->y > 0x50)
sprite->y -= 1;
}
#undef tState
#undef tDexNum
#undef tPalTimer
#undef tMonSpriteId
#undef tOtIdLo
#undef tOtIdHi
#undef tPersonalityLo
#undef tPersonalityHi
//************************************
//* *
//* Print data *
//* *
//************************************
static void PrintInfoScreenText(const u8 *str, u8 left, u8 top)
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_DYNAMIC_COLOR_6;
color[2] = TEXT_COLOR_LIGHT_GRAY;
AddTextPrinterParameterized4(0, 1, left, top, 0, 0, color, -1, str);
}
static void PrintInfoScreenTextWhite(const u8* str, u8 left, u8 top)
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_COLOR_WHITE;
color[2] = TEXT_DYNAMIC_COLOR_6;
AddTextPrinterParameterized4(0, FONT_NORMAL, left, top, 0, 0, color, TEXT_SKIP_DRAW, str);
}
static void PrintInfoScreenTextSmall(const u8* str, u8 left, u8 top)
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_DYNAMIC_COLOR_6;
color[2] = TEXT_COLOR_LIGHT_GRAY;
AddTextPrinterParameterized4(0, 0, left, top, 0, 0, color, 0, str);
}
static void UNUSED PrintInfoScreenTextSmallWhite(const u8* str, u8 left, u8 top)
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_COLOR_WHITE;
color[2] = TEXT_DYNAMIC_COLOR_6;
AddTextPrinterParameterized4(0, 0, left, top, 0, 0, color, 0, str);
}
//Stats screen
static void PrintStatsScreenTextSmall(u8 windowId, const u8* str, u8 left, u8 top)
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_DYNAMIC_COLOR_6;
color[2] = TEXT_COLOR_LIGHT_GRAY;
AddTextPrinterParameterized4(windowId, 0, left, top, 0, 0, color, 0, str);
}
static void PrintStatsScreenTextSmallWhite(u8 windowId, const u8* str, u8 left, u8 top)
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_COLOR_WHITE;
color[2] = TEXT_DYNAMIC_COLOR_6;
AddTextPrinterParameterized4(windowId, 0, left, top, 0, 0, color, 0, str);
}
//Type Icon
static void SetSpriteInvisibility(u8 spriteArrayId, bool8 invisible)
{
gSprites[sPokedexView->typeIconSpriteIds[spriteArrayId]].invisible = invisible;
}
static const u8 sContestCategoryToOamPaletteNum[CONTEST_CATEGORIES_COUNT] =
{
[CONTEST_CATEGORY_COOL] = 13,
[CONTEST_CATEGORY_BEAUTY] = 14,
[CONTEST_CATEGORY_CUTE] = 14,
[CONTEST_CATEGORY_SMART] = 15,
[CONTEST_CATEGORY_TOUGH] = 13,
};
static void SetTypeIconPosAndPal(u8 typeId, u8 x, u8 y, u8 spriteArrayId)
{
struct Sprite *sprite;
sprite = &gSprites[sPokedexView->typeIconSpriteIds[spriteArrayId]];
StartSpriteAnim(sprite, typeId);
if (typeId < NUMBER_OF_MON_TYPES)
sprite->oam.paletteNum = gTypesInfo[typeId].palette;
else
sprite->oam.paletteNum = sContestCategoryToOamPaletteNum[typeId - NUMBER_OF_MON_TYPES];
sprite->x = x + 16;
sprite->y = y + 8;
SetSpriteInvisibility(spriteArrayId, FALSE);
}
static void PrintCurrentSpeciesTypeInfo(u8 newEntry, u16 species)
{
u8 type1, type2;
if (!newEntry)
{
species = NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum);
}
//type icon(s)
#ifdef TX_RANDOMIZER_AND_CHALLENGES
type1 = GetTypeBySpecies(species, 1);
type2 = GetTypeBySpecies(species, 2);
#else
type1 = gSpeciesInfo[species].types[0];
type2 = gSpeciesInfo[species].types[1];
#endif
if (species == SPECIES_NONE)
type1 = type2 = TYPE_MYSTERY;
if (type1 == type2)
{
SetTypeIconPosAndPal(type1, 147, 48, 0);
SetSpriteInvisibility(1, TRUE);
}
else
{
SetTypeIconPosAndPal(type1, 147, 48, 0);
SetTypeIconPosAndPal(type2, 147 + 33, 48, 1);
}
}
static void CreateTypeIconSprites(void)
{
u8 i;
LoadCompressedSpriteSheet(&gSpriteSheet_MoveTypes);
LoadCompressedPalette(gMoveTypes_Pal, 0x1D0, 0x60);
for (i = 0; i < 2; i++)
{
if (sPokedexView->typeIconSpriteIds[i] == 0xFF)
sPokedexView->typeIconSpriteIds[i] = CreateSprite(&gSpriteTemplate_MoveTypes, 10, 10, 2);
SetSpriteInvisibility(i, TRUE);
}
}
// u32 value is re-used, but passed as a bool that's TRUE if national dex is enabled
static void PrintMonInfo(u32 num, u32 value, u32 owned, u32 newEntry)
{
u8 str[16];
u8 str2[32];
u16 species;
const u8 *name;
const u8 *category;
const u8 *description;
u8 digitCount = (NATIONAL_DEX_COUNT > 999 && value != 0) ? 4 : 3;
if (value == 0)
value = NationalToHoennOrder(num);
else
value = num;
ConvertIntToDecimalStringN(StringCopy(str, gText_NumberClear01), value, STR_CONV_MODE_LEADING_ZEROS, digitCount);
PrintInfoScreenTextWhite(str, 123, 17);
species = NationalPokedexNumToSpeciesHGSS(num);
if (species)
name = GetSpeciesName(species);
else
name = sText_TenDashes;
PrintInfoScreenTextWhite(name, 139 + (6 * digitCount), 17);
if (owned)
{
CopyMonCategoryText(species, str2);
category = str2;
}
else
{
category = gText_5MarksPokemon;
}
PrintInfoScreenText(category, 123, 31);
PrintMonMeasurements(species,owned);
if (owned)
description = GetSpeciesPokedexDescription(species);
else
description = sExpandedPlaceholder_PokedexDescription;
PrintInfoScreenText(description, GetStringCenterAlignXOffset(FONT_NORMAL, description, 0xF0), 93);
//Type Icon(s)
if (owned)
PrintCurrentSpeciesTypeInfo(newEntry, species);
}
// Unused in the English version, used to print height/weight in versions which use metric system.
static void UNUSED PrintDecimalNum(u8 windowId, u16 num, u8 left, u8 top)
{
u8 str[6];
bool8 outputted = FALSE;
u8 result;
result = num / 1000;
if (result == 0)
{
str[0] = CHAR_SPACER;
outputted = FALSE;
}
else
{
str[0] = CHAR_0 + result;
outputted = TRUE;
}
result = (num % 1000) / 100;
if (result == 0 && !outputted)
{
str[1] = CHAR_SPACER;
outputted = FALSE;
}
else
{
str[1] = CHAR_0 + result;
outputted = TRUE;
}
str[2] = CHAR_0 + ((num % 1000) % 100) / 10;
str[3] = CHAR_DEC_SEPARATOR;
str[4] = CHAR_0 + ((num % 1000) % 100) % 10;
str[5] = EOS;
PrintInfoSubMenuText(windowId, str, left, top);
}
static void PrintInfoSubMenuText(u8 windowId, const u8 *str, u8 left, u8 top)
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_DYNAMIC_COLOR_6;
color[2] = TEXT_COLOR_LIGHT_GRAY;
AddTextPrinterParameterized4(windowId, FONT_NORMAL, left, top, 0, 0, color, TEXT_SKIP_DRAW, str);
}
static u8 PrintCryScreenSpeciesName(u8 windowId, u16 num, u8 left, u8 top)
{
u8 str[POKEMON_NAME_LENGTH + 1];
u8 i;
for (i = 0; i < ARRAY_COUNT(str); i++)
str[i] = EOS;
num = NationalPokedexNumToSpeciesHGSS(num);
switch (num)
{
default:
for (i = 0; GetSpeciesName(num)[i] != EOS && i < POKEMON_NAME_LENGTH; i++)
str[i] = GetSpeciesName(num)[i];
break;
case 0:
for (i = 0; i < 5; i++)
str[i] = CHAR_HYPHEN;
break;
}
PrintInfoSubMenuText(windowId, str, left, top);
return i;
}
#define MALE_PERSONALITY 0xFE
// Unown and Spinda use the personality of the first seen individual of that species
// All others use personality 0
static u32 GetPokedexMonPersonality(u16 species)
{
if (species == SPECIES_UNOWN || species == SPECIES_SPINDA)
{
if (species == SPECIES_UNOWN)
return gSaveBlock2Ptr->pokedex.unownPersonality;
else
return gSaveBlock2Ptr->pokedex.spindaPersonality;
}
else
{
return MALE_PERSONALITY;
}
}
static u16 CreateMonSpriteFromNationalDexNumberHGSS(u16 nationalNum, s16 x, s16 y, u16 paletteSlot)
{
nationalNum = NationalPokedexNumToSpeciesHGSS(nationalNum);
return CreateMonPicSprite(nationalNum, FALSE, GetPokedexMonPersonality(nationalNum), TRUE, x, y, paletteSlot, TAG_NONE);
}
static u16 GetPokemonScaleFromNationalDexNumber(u16 nationalNum)
{
nationalNum = NationalPokedexNumToSpeciesHGSS(nationalNum);
return gSpeciesInfo[nationalNum].pokemonScale;
}
static u16 GetPokemonOffsetFromNationalDexNumber(u16 nationalNum)
{
nationalNum = NationalPokedexNumToSpeciesHGSS(nationalNum);
return gSpeciesInfo[nationalNum].pokemonOffset;
}
static u16 GetTrainerScaleFromNationalDexNumber(u16 nationalNum)
{
nationalNum = NationalPokedexNumToSpeciesHGSS(nationalNum);
return gSpeciesInfo[nationalNum].trainerScale;
}
static u16 GetTrainerOffsetFromNationalDexNumber(u16 nationalNum)
{
nationalNum = NationalPokedexNumToSpeciesHGSS(nationalNum);
return gSpeciesInfo[nationalNum].trainerOffset;
}
static u16 CreateSizeScreenTrainerPic(u16 species, s16 x, s16 y, s8 paletteSlot)
{
return CreateTrainerPicSprite(species, TRUE, x, y, paletteSlot, TAG_NONE);
}
//************************************
//* *
//* Helper functions *
//* *
//************************************
static void ResetOtherVideoRegisters(u16 regBits)
{
if (!(regBits & DISPCNT_BG0_ON))
{
ClearGpuRegBits(0, DISPCNT_BG0_ON);
SetGpuReg(REG_OFFSET_BG0CNT, 0);
SetGpuReg(REG_OFFSET_BG0HOFS, 0);
SetGpuReg(REG_OFFSET_BG0VOFS, 0);
}
if (!(regBits & DISPCNT_BG1_ON))
{
ClearGpuRegBits(0, DISPCNT_BG1_ON);
SetGpuReg(REG_OFFSET_BG1CNT, 0);
SetGpuReg(REG_OFFSET_BG1HOFS, 0);
SetGpuReg(REG_OFFSET_BG1VOFS, 0);
}
if (!(regBits & DISPCNT_BG2_ON))
{
ClearGpuRegBits(0, DISPCNT_BG2_ON);
SetGpuReg(REG_OFFSET_BG2CNT, 0);
SetGpuReg(REG_OFFSET_BG2HOFS, 0);
SetGpuReg(REG_OFFSET_BG2VOFS, 0);
}
if (!(regBits & DISPCNT_BG3_ON))
{
ClearGpuRegBits(0, DISPCNT_BG3_ON);
SetGpuReg(REG_OFFSET_BG3CNT, 0);
SetGpuReg(REG_OFFSET_BG3HOFS, 0);
SetGpuReg(REG_OFFSET_BG3VOFS, 0);
}
if (!(regBits & DISPCNT_OBJ_ON))
{
ClearGpuRegBits(0, DISPCNT_OBJ_ON);
ResetSpriteData();
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 8;
}
}
static void FreeWindowAndBgBuffers(void)
{
void *tilemapBuffer;
FreeAllWindowBuffers();
tilemapBuffer = GetBgTilemapBuffer(0);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(1);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(2);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(3);
if (tilemapBuffer)
Free(tilemapBuffer);
}
static u16 GetNextPosition(u8 direction, u16 position, u16 min, u16 max)
{
switch (direction)
{
case 1: // Up/Left
if (position > min)
position--;
break;
case 0: // Down/Right
if (position < max)
position++;
break;
case 3: // Up/Left with loop (unused)
if (position > min)
position--;
else
position = max;
break;
case 2: // Down/Right with loop (unused)
if (position < max)
position++;
else
position = min;
break;
}
return position;
}
//************************************
//* *
//* HGSS *
//* *
//************************************
static u16 NationalPokedexNumToSpeciesHGSS(u16 nationalNum)
{
if (!nationalNum)
return 0;
if (sPokedexView->formSpecies != 0)
return sPokedexView->formSpecies;
else
return NationalPokedexNumToSpecies(nationalNum);
}
static void LoadTilesetTilemapHGSS(u8 page)
{
switch (page)
{
case INFO_SCREEN:
if (!HGSS_DECAPPED)
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_1_Gfx, 0x2000, 0, 0);
else
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_1_Gfx, 0x2000, 0, 0);
CopyToBgTilemapBuffer(3, sPokedexPlusHGSS_ScreenInfo_Tilemap, 0, 0);
break;
case STATS_SCREEN:
if (!HGSS_DECAPPED)
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_1_Gfx, 0x2000, 0, 0);
else
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_1_Gfx, 0x2000, 0, 0);
CopyToBgTilemapBuffer(3, sPokedexPlusHGSS_ScreenStats_Tilemap, 0, 0);
break;
case EVO_SCREEN:
if (!HGSS_DECAPPED)
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_2_Gfx, 0x2000, 0, 0);
else
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_2_Gfx, 0x2000, 0, 0);
CopyToBgTilemapBuffer(3, sPokedexPlusHGSS_ScreenEvolution_Tilemap_PE, 0, 0);
break;
case FORMS_SCREEN:
if (!HGSS_DECAPPED)
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_2_Gfx, 0x2000, 0, 0);
else
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_2_Gfx, 0x2000, 0, 0);
CopyToBgTilemapBuffer(3, sPokedexPlusHGSS_ScreenForms_Tilemap, 0, 0);
break;
case CRY_SCREEN:
if (!HGSS_DECAPPED)
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_3_Gfx, 0x2000, 0, 0);
else
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_3_Gfx, 0x2000, 0, 0);
CopyToBgTilemapBuffer(3, sPokedexPlusHGSS_ScreenCry_Tilemap, 0, 0);
break;
case SIZE_SCREEN:
if (!HGSS_DECAPPED)
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_3_Gfx, 0x2000, 0, 0);
else
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_Menu_3_Gfx, 0x2000, 0, 0);
CopyToBgTilemapBuffer(3, sPokedexPlusHGSS_ScreenSize_Tilemap, 0, 0);
break;
}
}
//Physical/Special/Status category
static u8 ShowCategoryIcon(u32 category)
{
if (sPokedexView->categoryIconSpriteId == 0xFF)
sPokedexView->categoryIconSpriteId = CreateSprite(&gSpriteTemplate_CategoryIcons, 139, 90, 0);
gSprites[sPokedexView->categoryIconSpriteId].invisible = FALSE;
StartSpriteAnim(&gSprites[sPokedexView->categoryIconSpriteId], category);
return sPokedexView->categoryIconSpriteId;
}
static void DestroyCategoryIcon(void)
{
if (sPokedexView->categoryIconSpriteId != 0xFF)
DestroySprite(&gSprites[sPokedexView->categoryIconSpriteId]);
sPokedexView->categoryIconSpriteId = 0xFF;
}
//************************************
//* *
//* STATS *
//* *
//************************************
static const u8 sStatsPageNavigationTextColor[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY};
static void StatsPage_PrintNavigationButtons(void)
{
u8 x = 9;
u8 y = 0;
if (!HGSS_DECAPPED)
AddTextPrinterParameterized3(WIN_STATS_NAVIGATION_BUTTONS, 0, x, y, sStatsPageNavigationTextColor, 0, sText_Stats_Buttons);
else
AddTextPrinterParameterized3(WIN_STATS_NAVIGATION_BUTTONS, 0, x, y, sStatsPageNavigationTextColor, 0, sText_Stats_Buttons_Decapped);
PutWindowTilemap(WIN_STATS_NAVIGATION_BUTTONS);
CopyWindowToVram(WIN_STATS_NAVIGATION_BUTTONS, 3);
}
static void ResetStatsWindows(void)
{
u8 i;
FreeAllWindowBuffers();
InitWindows(sStatsScreen_WindowTemplates);
for (i = 0; i < WIN_STATS_END + 1; i++)
{
FillWindowPixelBuffer(i, PIXEL_FILL(0));
PutWindowTilemap(i);
CopyWindowToVram(i, COPYWIN_FULL);
}
}
static void SaveMonDataInStruct(void)
{
u16 species = NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum);
u8 evs[NUM_STATS] =
{
[STAT_HP] = gSpeciesInfo[species].evYield_HP,
[STAT_ATK] = gSpeciesInfo[species].evYield_Speed,
[STAT_DEF] = gSpeciesInfo[species].evYield_Attack,
[STAT_SPEED] = gSpeciesInfo[species].evYield_SpAttack,
[STAT_SPATK] = gSpeciesInfo[species].evYield_Defense,
[STAT_SPDEF] = gSpeciesInfo[species].evYield_SpDefense
};
u8 differentEVs = 0;
u8 i;
//Count how many different EVs
for (i = 0; i < NUM_STATS; i++)
{
if (evs[i] > 0) //HP//Speed//Attack//Special Attack//Defense//Special Defense
differentEVs++;
}
sPokedexView->sPokemonStats.species = species;
sPokedexView->sPokemonStats.genderRatio = gSpeciesInfo[species].genderRatio;
sPokedexView->sPokemonStats.baseHP = gSpeciesInfo[species].baseHP;
sPokedexView->sPokemonStats.baseSpeed = gSpeciesInfo[species].baseSpeed;
sPokedexView->sPokemonStats.baseAttack = gSpeciesInfo[species].baseAttack;
sPokedexView->sPokemonStats.baseSpAttack = gSpeciesInfo[species].baseSpAttack;
sPokedexView->sPokemonStats.baseDefense = gSpeciesInfo[species].baseDefense;
sPokedexView->sPokemonStats.baseSpDefense = gSpeciesInfo[species].baseSpDefense;
sPokedexView->sPokemonStats.differentEVs = differentEVs;
sPokedexView->sPokemonStats.evYield_HP = evs[STAT_HP];
sPokedexView->sPokemonStats.evYield_Speed = evs[STAT_ATK];
sPokedexView->sPokemonStats.evYield_Attack = evs[STAT_DEF];
sPokedexView->sPokemonStats.evYield_SpAttack = evs[STAT_SPEED];
sPokedexView->sPokemonStats.evYield_Defense = evs[STAT_SPATK];
sPokedexView->sPokemonStats.evYield_SpDefense = evs[STAT_SPDEF];
sPokedexView->sPokemonStats.catchRate = gSpeciesInfo[species].catchRate;
sPokedexView->sPokemonStats.growthRate = gSpeciesInfo[species].growthRate;
sPokedexView->sPokemonStats.eggGroup1 = gSpeciesInfo[species].eggGroups[0];
sPokedexView->sPokemonStats.eggGroup2 = gSpeciesInfo[species].eggGroups[1];
sPokedexView->sPokemonStats.eggCycles = gSpeciesInfo[species].eggCycles;
sPokedexView->sPokemonStats.expYield = gSpeciesInfo[species].expYield;
sPokedexView->sPokemonStats.friendship = gSpeciesInfo[species].friendship;
sPokedexView->sPokemonStats.ability0 = GetAbilityBySpecies(species, 0);
sPokedexView->sPokemonStats.ability1 = GetAbilityBySpecies(species, 1);
sPokedexView->sPokemonStats.abilityHidden = GetAbilityBySpecies(species, 2);
}
#define tMonSpriteId data[4]
static void Task_LoadStatsScreen(u8 taskId)
{
switch (gMain.state)
{
case 0:
default:
if (!gPaletteFade.active)
{
u16 r2;
sPokedexView->currentPage = STATS_SCREEN;
gPokedexVBlankCB = gMain.vblankCallback;
SetVBlankCallback(NULL);
r2 = 0;
if (gTasks[taskId].data[1] != 0)
r2 += DISPCNT_OBJ_ON;
if (gTasks[taskId].data[2] != 0)
r2 |= DISPCNT_BG1_ON;
ResetOtherVideoRegisters(r2);
gMain.state = 1;
}
break;
case 1:
LoadTilesetTilemapHGSS(STATS_SCREEN);
ResetStatsWindows();
CopyBgTilemapBufferToVram(1);
CopyBgTilemapBufferToVram(2);
CopyBgTilemapBufferToVram(3);
gMain.state++;
break;
case 2:
LoadScreenSelectBarMain(0xD);
LoadPokedexBgPalette(sPokedexView->isSearchResults);
gMain.state++;
break;
case 3:
sPokedexView->typeIconSpriteIds[0] = 0xFF;
sPokedexView->typeIconSpriteIds[1] = 0xFF;
CreateTypeIconSprites();
sPokedexView->categoryIconSpriteId = 0xFF;
LoadCompressedPalette(gMoveTypes_Pal, 0x1D0, 0x60);
LoadCompressedSpriteSheet(&gSpriteSheet_CategoryIcons);
LoadSpritePalette(&gSpritePal_CategoryIcons);
gMain.state++;
break;
case 4:
SaveMonDataInStruct();
sPokedexView->moveSelected = 0;
sPokedexView->movesTotal = 0;
sPokedexView->numEggMoves = 0;
sPokedexView->numLevelUpMoves = 0;
sPokedexView->numTMHMMoves = 0;
if (CalculateMoves())
gMain.state++;
break;
case 5:
if (gTasks[taskId].data[1] == 0)
{
//Icon
u32 species = NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum);
u32 personality = GetPokedexMonPersonality(species);
FreeMonIconPalettes(); //Free space for new pallete
LoadMonIconPalettePersonality(species, personality); //Loads pallete for current mon
gTasks[taskId].data[6] = CreateMonIcon(species, SpriteCB_MonIcon, 18, 31, 4, personality); //Create pokemon sprite
gSprites[gTasks[taskId].data[4]].oam.priority = 0;
}
gMain.state++;
break;
case 6:
gTasks[taskId].data[5] = 0;
PrintStatsScreen_NameGender(taskId, sPokedexListItem->dexNum, sPokedexView->dexMode == DEX_MODE_HOENN ? FALSE : TRUE);
PrintStatsScreen_Left(taskId);
PrintStatsScreen_Abilities(taskId);
PrintStatsScreen_Moves_Top(taskId);
PrintStatsScreen_Moves_Description(taskId);
PrintStatsScreen_Moves_BottomText(taskId);
PrintStatsScreen_Moves_Bottom(taskId);
if (!sPokedexListItem->owned)
LoadPalette(gPlttBufferUnfaded + 1, 0x31, 0x1E);
StatsPage_PrintNavigationButtons(); //sText_Stats_Buttons
gMain.state++;
break;
case 7:
{
u32 preservedPalettes = 0;
if (gTasks[taskId].data[2] != 0)
preservedPalettes = 0x14; // each bit represents a palette index
if (gTasks[taskId].data[1] != 0)
preservedPalettes |= (1 << (gSprites[gTasks[taskId].tMonSpriteId].oam.paletteNum + 16));
BeginNormalPaletteFade(~preservedPalettes, 0, 16, 0, RGB_BLACK);
SetVBlankCallback(gPokedexVBlankCB);
gMain.state++;
break;
}
case 8:
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
HideBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 9:
if (!gPaletteFade.active)
gMain.state++;
break;
case 10:
gMain.state++;
break;
case 11:
gTasks[taskId].data[0] = 0;
gTasks[taskId].data[1] = 0;
gTasks[taskId].data[2] = 1;
gTasks[taskId].func = Task_HandleStatsScreenInput;
gMain.state = 0;
break;
}
}
static void UNUSED FreeStatsScreenWindowAndBgBuffers(void)
{
void *tilemapBuffer;
FreeAllWindowBuffers();
tilemapBuffer = GetBgTilemapBuffer(0);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(1);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(2);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(3);
if (tilemapBuffer)
Free(tilemapBuffer);
}
static void Task_HandleStatsScreenInput(u8 taskId)
{
if (JOY_NEW(A_BUTTON))
{
PlaySE(SE_DEX_PAGE);
if (gTasks[taskId].data[5] == 0)
gTasks[taskId].data[5] = 1;
else
gTasks[taskId].data[5] = 0;
FillWindowPixelBuffer(WIN_STATS_LEFT, PIXEL_FILL(0));
PrintStatsScreen_Left(taskId);
FillWindowPixelBuffer(WIN_STATS_MOVES_DESCRIPTION, PIXEL_FILL(0));
PrintStatsScreen_Moves_Description(taskId);
FillWindowPixelBuffer(WIN_STATS_MOVES_BOTTOM, PIXEL_FILL(0));
PrintStatsScreen_Moves_BottomText(taskId);
PrintStatsScreen_Moves_Bottom(taskId);
FillWindowPixelBuffer(WIN_STATS_ABILITIES, PIXEL_FILL(0));
PrintStatsScreen_Abilities(taskId);
}
if (JOY_NEW(B_BUTTON))
{
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK);
gTasks[taskId].func = Task_ExitStatsScreen;
PlaySE(SE_PC_OFF);
return;
}
//Change moves
if (JOY_REPEAT(DPAD_UP) && sPokedexView->moveSelected > 0)
{
sPokedexView->moveSelected -= 1;
PlaySE(SE_SELECT);
FillWindowPixelBuffer(WIN_STATS_MOVES_TOP, PIXEL_FILL(0));
PrintStatsScreen_DestroyMoveItemIcon(taskId);
PrintStatsScreen_Moves_Top(taskId);
FillWindowPixelBuffer(WIN_STATS_MOVES_DESCRIPTION, PIXEL_FILL(0));
PrintStatsScreen_Moves_Description(taskId);
FillWindowPixelRect(WIN_STATS_MOVES_BOTTOM, PIXEL_FILL(0), 50, 0, 20, 16);
FillWindowPixelRect(WIN_STATS_MOVES_BOTTOM, PIXEL_FILL(0), 120, 0, 20, 16);
PrintStatsScreen_Moves_Bottom(taskId);
}
if (JOY_REPEAT(DPAD_DOWN) && sPokedexView->moveSelected < sPokedexView->movesTotal -1 )
{
sPokedexView->moveSelected = sPokedexView->moveSelected + 1;
PlaySE(SE_SELECT);
FillWindowPixelBuffer(WIN_STATS_MOVES_TOP, PIXEL_FILL(0));
PrintStatsScreen_DestroyMoveItemIcon(taskId);
PrintStatsScreen_Moves_Top(taskId);
FillWindowPixelBuffer(WIN_STATS_MOVES_DESCRIPTION, PIXEL_FILL(0));
PrintStatsScreen_Moves_Description(taskId);
FillWindowPixelRect(WIN_STATS_MOVES_BOTTOM, PIXEL_FILL(0), 50, 0, 20, 16);
FillWindowPixelRect(WIN_STATS_MOVES_BOTTOM, PIXEL_FILL(0), 120, 0, 20, 16);
PrintStatsScreen_Moves_Bottom(taskId);
}
//Switch screens
if ((JOY_NEW(DPAD_LEFT) || (JOY_NEW(L_BUTTON) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_LR)))
{
sPokedexView->selectedScreen = INFO_SCREEN;
BeginNormalPaletteFade(0xFFFFFFEB, 0, 0, 0x10, RGB_BLACK);
sPokedexView->screenSwitchState = 1;
gTasks[taskId].func = Task_SwitchScreensFromStatsScreen;
PlaySE(SE_PIN);
}
if ((JOY_NEW(DPAD_RIGHT) || (JOY_NEW(R_BUTTON) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_LR)))
{
if (!sPokedexListItem->owned)
PlaySE(SE_FAILURE);
else
{
sPokedexView->selectedScreen = EVO_SCREEN;
BeginNormalPaletteFade(0xFFFFFFEB, 0, 0, 0x10, RGB_BLACK);
sPokedexView->screenSwitchState = 3;
gTasks[taskId].func = Task_SwitchScreensFromStatsScreen;
PlaySE(SE_PIN);
}
}
}
#define ITEM_TAG 0xFDF3
static void PrintStatsScreen_DestroyMoveItemIcon(u8 taskId)
{
FreeSpriteTilesByTag(ITEM_TAG); //Destroy item icon
FreeSpritePaletteByTag(ITEM_TAG); //Destroy item icon
FreeSpriteOamMatrix(&gSprites[gTasks[taskId].data[3]]); //Destroy item icon
DestroySprite(&gSprites[gTasks[taskId].data[3]]); //Destroy item icon
}
static bool8 CalculateMoves(void)
{
u16 species = NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum);
const u16 *teachableLearnset = GetSpeciesTeachableLearnset(species);
u16 statsMovesEgg[EGG_MOVES_ARRAY_COUNT] = {0};
u16 statsMovesLevelUp[MAX_LEVEL_UP_MOVES] = {0};
u16 move;
u8 numEggMoves = 0;
u8 numLevelUpMoves = 0;
u8 numTMHMMoves = 0;
u8 numTutorMoves = 0;
u16 movesTotal = 0;
u8 i,j;
// Mega pokemon don't have distinct learnsets from their base form; so use base species for calculation
if (species >= SPECIES_VENUSAUR_MEGA && species <= SPECIES_GROUDON_PRIMAL)
species = GetFormSpeciesId(species, 0);
//Calculate amount of Egg and LevelUp moves
numEggMoves = GetEggMovesBySpecies(species, statsMovesEgg);
numLevelUpMoves = GetLevelUpMovesBySpecies(species, statsMovesLevelUp);
//Egg moves
for (i=0; i < numEggMoves; i++)
{
sStatsMoves[movesTotal] = statsMovesEgg[i];
movesTotal++;
}
//Level up moves
for (i=0; i < numLevelUpMoves; i++)
{
sStatsMoves[movesTotal] = statsMovesLevelUp[i];
movesTotal++;
}
for (i = 0; teachableLearnset[i] != MOVE_UNAVAILABLE; i++)
{
move = teachableLearnset[i];
for (j = 0; j < NUM_TECHNICAL_MACHINES + NUM_HIDDEN_MACHINES; j++)
{
if (ItemIdToBattleMoveId(ITEM_TM01 + j) == move)
{
sStatsMovesTMHM_ID[numTMHMMoves] = (ITEM_TM01 + j);
numTMHMMoves++;
sStatsMoves[movesTotal] = move;
movesTotal++;
break;
}
}
}
for (i = 0; teachableLearnset[i] != MOVE_UNAVAILABLE; i++)
{
move = teachableLearnset[i];
for (j = 0; j < NUM_TECHNICAL_MACHINES + NUM_HIDDEN_MACHINES; j++)
{
if (ItemIdToBattleMoveId(ITEM_TM01 + j) == move)
break;
}
if (j >= NUM_TECHNICAL_MACHINES + NUM_HIDDEN_MACHINES)
{
numTutorMoves++;
sStatsMoves[movesTotal] = move;
movesTotal++;
}
}
sPokedexView->numEggMoves = numEggMoves;
sPokedexView->numLevelUpMoves = numLevelUpMoves;
sPokedexView->numTMHMMoves = numTMHMMoves;
sPokedexView->numTutorMoves = numTutorMoves;
sPokedexView->movesTotal = movesTotal;
return TRUE;
}
static void PrintStatsScreen_Moves_Top(u8 taskId)
{
u8 numEggMoves = sPokedexView->numEggMoves;
u8 numLevelUpMoves = sPokedexView->numLevelUpMoves;
u8 numTMHMMoves = sPokedexView->numTMHMMoves;
u8 numTutorMoves = sPokedexView->numTutorMoves;
u8 movesTotal = sPokedexView->movesTotal;
u8 selected = sPokedexView->moveSelected;
u8 level;
u8 moves_x = 5;
u8 moves_y = 3;
u16 move;
u16 item;
u16 species = NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum);
//Move
move = sStatsMoves[selected];
//Moves selected from move max
ConvertIntToDecimalStringN(gStringVar1, (selected+1), STR_CONV_MODE_RIGHT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar2, movesTotal, STR_CONV_MODE_RIGHT_ALIGN, 3);
StringExpandPlaceholders(gStringVar1, sText_Stats_MoveSelectedMax);
PrintStatsScreenTextSmallWhite(WIN_STATS_MOVES_TOP, gStringVar1, moves_x-1, moves_y+1);
//Move name
StringCopy(gStringVar3, GetMoveName(move));
StringCopyPadded(gStringVar3, gStringVar3, CHAR_SPACE, 20);
PrintStatsScreenTextSmall(WIN_STATS_MOVES_TOP, gStringVar3, moves_x, moves_y + 17);
//Draw move type icon
if (gTasks[taskId].data[5] == 0)
{
SetTypeIconPosAndPal(gMovesInfo[move].type, moves_x + 146, moves_y + 17, 0);
SetSpriteInvisibility(1, TRUE);
}
else
{
SetTypeIconPosAndPal(NUMBER_OF_MON_TYPES + gMovesInfo[move].contestCategory, moves_x + 146, moves_y + 17, 1);
SetSpriteInvisibility(0, TRUE);
}
//Calculate and retrieve correct move from the arrays
if (selected < numEggMoves)
{
PrintStatsScreenTextSmall(WIN_STATS_MOVES_TOP, gText_ThreeDashes, moves_x + 113, moves_y + 9);
item = ITEM_LUCKY_EGG;
}
else if (selected < (numEggMoves + numLevelUpMoves))
{
level = GetSpeciesLevelUpLearnset(species)[(selected-numEggMoves)].level;
ConvertIntToDecimalStringN(gStringVar1, level, STR_CONV_MODE_LEFT_ALIGN, 3); //Move learn lvl
PrintStatsScreenTextSmall(WIN_STATS_MOVES_TOP, sText_Stats_MoveLevel, moves_x + 113, moves_y + 3); //Level text
PrintStatsScreenTextSmall(WIN_STATS_MOVES_TOP, gStringVar1, moves_x + 113, moves_y + 14); //Print level
item = ITEM_RARE_CANDY;
}
else if (selected < (numEggMoves + numLevelUpMoves + numTMHMMoves))
{
CopyItemName(sStatsMovesTMHM_ID[(selected-numEggMoves-numLevelUpMoves)], gStringVar1); //TM name
PrintStatsScreenTextSmall(WIN_STATS_MOVES_TOP, gStringVar1, moves_x + 113, moves_y + 9);
item = sStatsMovesTMHM_ID[(selected-numEggMoves-numLevelUpMoves)];
}
else if (selected < (numEggMoves + numLevelUpMoves + numTMHMMoves + numTutorMoves))
{
PrintStatsScreenTextSmall(WIN_STATS_MOVES_TOP, gText_ThreeDashes, moves_x + 113, moves_y + 9);
item = ITEM_TEACHY_TV;
}
else
{
StringCopy(gStringVar4, gText_CommunicationError);
item = ITEM_MASTER_BALL;
}
//Egg/TM/Level/Tutor Item Icon
gTasks[taskId].data[3] = AddItemIconSprite(ITEM_TAG, ITEM_TAG, item);
gSprites[gTasks[taskId].data[3]].x2 = 203;
gSprites[gTasks[taskId].data[3]].y2 = 39;
gSprites[gTasks[taskId].data[3]].oam.priority = 0;
}
static void PrintStatsScreen_Moves_Description(u8 taskId)
{
u8 selected = sPokedexView->moveSelected;
u16 move;
u8 moves_x = 5;
u8 moves_y = 5;
//Move
move = sStatsMoves[selected];
//Move description
if (gTasks[taskId].data[5] == 0)
{
StringCopy(gStringVar4, gMovesInfo[move].description);
PrintStatsScreenTextSmall(WIN_STATS_MOVES_DESCRIPTION, gStringVar4, moves_x, moves_y);
}
else
{
StringCopy(gStringVar4, gContestEffectDescriptionPointers[gMovesInfo[move].contestEffect]);
PrintStatsScreenTextSmall(WIN_STATS_MOVES_DESCRIPTION, gStringVar4, moves_x, moves_y);
}
}
static void PrintStatsScreen_Moves_BottomText(u8 taskId)
{
u8 moves_x = 8;
u8 moves_y = 3;
if (gTasks[taskId].data[5] == 0)
{
PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gText_Power, moves_x, moves_y);
PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gText_Accuracy2, moves_x + 66, moves_y);
}
else
{
PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gText_Appeal, moves_x, moves_y);
PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gText_Jam, moves_x + 66, moves_y);
}
}
static void PrintStatsScreen_Moves_Bottom(u8 taskId)
{
u8 moves_x = 8;
u8 moves_y = 3;
u8 selected = sPokedexView->moveSelected;
u16 move;
//Contest
u8 contest_effectValue;
u8 contest_appeal = 0;
u8 contest_jam = 0;
//Move
move = sStatsMoves[selected];
//Power + Accuracy
if (gTasks[taskId].data[5] == 0)
{
//Power
if (gMovesInfo[move].power < 2)
StringCopy(gStringVar1, gText_ThreeDashes);
else
ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[move].power, STR_CONV_MODE_RIGHT_ALIGN, 3);
PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gStringVar1, moves_x + 45, moves_y);
//Physical/Special/Status Category
DestroyCategoryIcon();
ShowCategoryIcon(GetBattleMoveCategory(move));
//Accuracy
if (gMovesInfo[move].accuracy == 0)
StringCopy(gStringVar1, gText_ThreeDashes);
else
ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[move].accuracy, STR_CONV_MODE_RIGHT_ALIGN, 3);
PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gStringVar1, moves_x + 114, moves_y);
}
else //Appeal + Jam
{
DestroyCategoryIcon();
gSprites[sPokedexView->categoryIconSpriteId].invisible = TRUE;
//Appeal
contest_effectValue = gContestEffects[gMovesInfo[move].contestEffect].appeal;
if (contest_effectValue != 0xFF)
contest_appeal = contest_effectValue / 10;
ConvertIntToDecimalStringN(gStringVar1, contest_appeal, STR_CONV_MODE_RIGHT_ALIGN, 1);
StringCopy(gStringVar2, sText_PlusSymbol);
StringAppend(gStringVar2, gStringVar1);
PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gStringVar2, moves_x + 45, moves_y);
//Jam
contest_effectValue = gContestEffects[gMovesInfo[move].contestEffect].jam;
if (contest_effectValue != 0xFF)
contest_jam = contest_effectValue / 10;
ConvertIntToDecimalStringN(gStringVar1, contest_jam, STR_CONV_MODE_RIGHT_ALIGN, 1);
StringCopy(gStringVar2, sText_Stats_Minus);
StringAppend(gStringVar2, gStringVar1);
PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gStringVar2, moves_x + 119, moves_y);
}
}
static void PrintStatsScreen_NameGender(u8 taskId, u32 num, u32 value)
{
u8 str[16];
u16 species = NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum);
u8 base_x = 38;
u8 base_y = 0;
u8 gender_x, gender_y;
//Name
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, GetSpeciesName(species), base_x, base_y);
//Number
if (value == 0)
value = NationalToHoennOrder(num);
else
value = num;
ConvertIntToDecimalStringN(StringCopy(str, gText_NumberClear01), value, STR_CONV_MODE_LEADING_ZEROS, 3);
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, str, base_x, base_y + 10);
//Gender ratio //MON_GENDERLESS == 0xFF
gender_x = base_x;
gender_y = base_y + 20;
switch (sPokedexView->sPokemonStats.genderRatio)
{
case 0:
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, sText_Stats_Gender_0, gender_x, gender_y);
break;
case 31:
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, sText_Stats_Gender_12_5, gender_x, gender_y);
break;
case 63:
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, sText_Stats_Gender_25, gender_x, gender_y);
break;
case 127:
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, sText_Stats_Gender_50, gender_x, gender_y);
break;
case 191:
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, sText_Stats_Gender_75, gender_x, gender_y);
break;
case 223:
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, sText_Stats_Gender_87_5, gender_x, gender_y);
break;
case 254:
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, sText_Stats_Gender_100, gender_x, gender_y);
break;
default:
PrintStatsScreenTextSmall(WIN_STATS_NAME_GENDER, gText_ThreeDashes, gender_x, gender_y);
break;
}
}
static u8 PrintMonStatsToggle_DifferentEVsColumn(u8 differentEVs)
{
if (differentEVs == 1 || differentEVs == 3)
return 0;
else
return 1;
}
static u8 PrintMonStatsToggle_DifferentEVsRow(u8 differentEVs)
{
if (differentEVs == 1 || differentEVs == 2)
return 0;
else
return 1;
}
static u8* PrintMonStatsToggle_EV_Arrows(u8 *dest, u8 value)
{
switch (value)
{
case 1:
StringCopy(dest, sText_Stats_EV_Plus1);
break;
case 2:
StringCopy(dest, sText_Stats_EV_Plus2);
break;
case 3:
StringCopy(dest, sText_Stats_EV_Plus3);
break;
}
return dest;
}
static void PrintStatsScreen_Left(u8 taskId)
{
u8 base_x = 8;
u8 x_offset_column = 43;
u8 column = 0;
u8 base_x_offset = 70;
u8 base_x_first_row = 23;
u8 base_x_second_row = 43;
u8 base_y_offset = 11;
u8 base_i = 0;
u8 base_y = 5;
u32 align_x;
u8 total_x = 93;
u8 strEV[25];
u8 strBase[14];
u8 EVs[6] = {sPokedexView->sPokemonStats.evYield_HP, sPokedexView->sPokemonStats.evYield_Speed, sPokedexView->sPokemonStats.evYield_Attack, sPokedexView->sPokemonStats.evYield_SpAttack, sPokedexView->sPokemonStats.evYield_Defense, sPokedexView->sPokemonStats.evYield_SpDefense};
u8 differentEVs = 0;
//Base stats
if (gTasks[taskId].data[5] == 0)
{
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_HP, base_x, base_y + base_y_offset*base_i);
ConvertIntToDecimalStringN(strBase, sPokedexView->sPokemonStats.baseHP, STR_CONV_MODE_RIGHT_ALIGN, 3);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, strBase, base_x+base_x_first_row, base_y + base_y_offset*base_i);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_Speed, base_x+base_x_second_row, base_y + base_y_offset*base_i);
ConvertIntToDecimalStringN(strBase, sPokedexView->sPokemonStats.baseSpeed, STR_CONV_MODE_RIGHT_ALIGN, 3);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, strBase, base_x+base_x_offset, base_y + base_y_offset*base_i);
base_i++;
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_Attack, base_x, base_y + base_y_offset*base_i);
ConvertIntToDecimalStringN(strBase, sPokedexView->sPokemonStats.baseAttack, STR_CONV_MODE_RIGHT_ALIGN, 3);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, strBase, base_x+base_x_first_row, base_y + base_y_offset*base_i);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_SpAttack, base_x+base_x_second_row, base_y + base_y_offset*base_i);
ConvertIntToDecimalStringN(strBase, sPokedexView->sPokemonStats.baseSpAttack, STR_CONV_MODE_RIGHT_ALIGN, 3);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, strBase, base_x+base_x_offset, base_y + base_y_offset*base_i);
base_i++;
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_Defense, base_x, base_y + base_y_offset*base_i);
ConvertIntToDecimalStringN(strBase, sPokedexView->sPokemonStats.baseDefense, STR_CONV_MODE_RIGHT_ALIGN, 3);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, strBase, base_x+base_x_first_row, base_y + base_y_offset*base_i);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_SpDefense, base_x+base_x_second_row, base_y + base_y_offset*base_i);
ConvertIntToDecimalStringN(strBase, sPokedexView->sPokemonStats.baseSpDefense, STR_CONV_MODE_RIGHT_ALIGN, 3);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, strBase, base_x+base_x_offset, base_y + base_y_offset*base_i);
base_i++;
}
else //EV increases
{
//If 1 or 2 EVs display with the same layout as the base stats
if (sPokedexView->sPokemonStats.differentEVs < 3)
{
differentEVs = 0;
//HP
if (EVs[0] > 0)
{
differentEVs++;
column = PrintMonStatsToggle_DifferentEVsColumn(differentEVs);
base_i = PrintMonStatsToggle_DifferentEVsRow(differentEVs);
StringCopy(gStringVar1, sText_Stats_HP);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[0]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + x_offset_column*column, base_y + base_y_offset*base_i);
}
//Speed
if (EVs[1]> 0)
{
differentEVs++;
column = PrintMonStatsToggle_DifferentEVsColumn(differentEVs);
base_i = PrintMonStatsToggle_DifferentEVsRow(differentEVs);
StringCopy(gStringVar1, sText_Stats_Speed);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[1]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + x_offset_column*column, base_y + base_y_offset*base_i);
}
//Attack
if (EVs[2] > 0)
{
differentEVs++;
column = PrintMonStatsToggle_DifferentEVsColumn(differentEVs);
base_i = PrintMonStatsToggle_DifferentEVsRow(differentEVs);
StringCopy(gStringVar1, sText_Stats_Attack);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[2]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + x_offset_column*column, base_y + base_y_offset*base_i);
}
//Special Attack
if (EVs[3] > 0)
{
differentEVs++;
column = PrintMonStatsToggle_DifferentEVsColumn(differentEVs);
base_i = PrintMonStatsToggle_DifferentEVsRow(differentEVs);
StringCopy(gStringVar1, sText_Stats_SpAttack);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[3]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + x_offset_column*column, base_y + base_y_offset*base_i);
}
//Defense
if (EVs[4] > 0)
{
differentEVs++;
column = PrintMonStatsToggle_DifferentEVsColumn(differentEVs);
base_i = PrintMonStatsToggle_DifferentEVsRow(differentEVs);
StringCopy(gStringVar1, sText_Stats_Defense);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[4]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + x_offset_column*column, base_y + base_y_offset*base_i);
}
//Special Defense
if (EVs[5] > 0)
{
differentEVs++;
column = PrintMonStatsToggle_DifferentEVsColumn(differentEVs);
base_i = PrintMonStatsToggle_DifferentEVsRow(differentEVs);
StringCopy(gStringVar1, sText_Stats_SpDefense);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[5]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + x_offset_column*column, base_y + base_y_offset*base_i);
}
}
else //3 different EVs in 1 row
{
column = 0;
//HP
if (EVs[0] > 0)
{
StringCopy(gStringVar1, sText_Stats_HP);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[0]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + 29*column, base_y + base_y_offset*base_i);
column++;
}
//Speed
if (EVs[1] > 0)
{
StringCopy(gStringVar1, sText_Stats_Speed);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[1]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + 29*column, base_y + base_y_offset*base_i);
column++;
}
//Attack
if (EVs[2] > 0)
{
StringCopy(gStringVar1, sText_Stats_Attack);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[2]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + 29*column, base_y + base_y_offset*base_i);
column++;
}
//Special Attack
if (EVs[3] > 0)
{
StringCopy(gStringVar1, sText_Stats_SpAttack);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[3]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + 29*column, base_y + base_y_offset*base_i);
column++;
}
//Defense
if (EVs[4] > 0)
{
StringCopy(gStringVar1, sText_Stats_Defense);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[4]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + 29*column, base_y + base_y_offset*base_i);
column++;
}
//Special Defense
if (EVs[5] > 0)
{
StringCopy(gStringVar1, sText_Stats_SpDefense);
PrintMonStatsToggle_EV_Arrows(gStringVar2, EVs[5]);
StringExpandPlaceholders(gStringVar3, sText_Stats_EvStr1Str2);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x + 29*column, base_y + base_y_offset*base_i);
column++;
}
}
base_i++;
}
//TOGGLE--------------------------------------
if (gTasks[taskId].data[5] == 0)
{
u32 catchRate = sPokedexView->sPokemonStats.catchRate;
u32 growthRate = sPokedexView->sPokemonStats.growthRate;
//Catch rate
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_CatchRate, base_x, base_y + base_y_offset*base_i);
if (catchRate <= 10)
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_CatchRate_Legend, base_x + x_offset_column, base_y + base_y_offset*base_i);
else if (catchRate <= 70)
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_CatchRate_VeryHard, base_x + x_offset_column, base_y + base_y_offset*base_i);
else if (catchRate <= 100)
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_CatchRate_Difficult, base_x + x_offset_column, base_y + base_y_offset*base_i);
else if (catchRate <= 150)
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_CatchRate_Medium, base_x + x_offset_column, base_y + base_y_offset*base_i);
else if (catchRate <= 200)
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_CatchRate_Relaxed, base_x + x_offset_column, base_y + base_y_offset*base_i);
else
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_CatchRate_Easy, base_x + x_offset_column, base_y + base_y_offset*base_i);
base_i++;
//Growth rate
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_Growthrate, base_x, base_y + base_y_offset*base_i);
switch (growthRate)
{
case GROWTH_MEDIUM_FAST:
StringCopy(strEV, sText_Stats_MEDIUM_FAST);
break;
case GROWTH_ERRATIC:
StringCopy(strEV, sText_Stats_ERRATIC);
break;
case GROWTH_FLUCTUATING:
StringCopy(strEV, sText_Stats_FLUCTUATING);
break;
case GROWTH_MEDIUM_SLOW:
StringCopy(strEV, sText_Stats_MEDIUM_SLOW);
break;
case GROWTH_FAST:
StringCopy(strEV, sText_Stats_FAST);
break;
case GROWTH_SLOW:
StringCopy(strEV, sText_Stats_SLOW);
break;
default:
break;
}
align_x = GetStringRightAlignXOffset(0, strEV, total_x);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, strEV, align_x, base_y + base_y_offset*base_i);
}
else
{
//Exp Yield
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_ExpYield, base_x, base_y + base_y_offset*base_i);
ConvertIntToDecimalStringN(gStringVar1, sPokedexView->sPokemonStats.expYield, STR_CONV_MODE_RIGHT_ALIGN, 3);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar1, base_x + base_x_offset, base_y + base_y_offset*base_i);
base_i++;
//Friendship
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_Friendship, base_x, base_y + base_y_offset*base_i);
switch (sPokedexView->sPokemonStats.friendship)
{
case 35:
StringCopy(strEV, sText_Stats_Friendship_BigAnger);
break;
case 70:
StringCopy(strEV, sText_Stats_Friendship_Neutral);
break;
case 90:
StringCopy(strEV, sText_Stats_Friendship_Happy);
break;
case 100:
StringCopy(strEV, sText_Stats_Friendship_Happy);
break;
case 140:
StringCopy(strEV, sText_Stats_Friendship_BigSmile);
break;
default:
ConvertIntToDecimalStringN(strEV, sPokedexView->sPokemonStats.friendship, STR_CONV_MODE_RIGHT_ALIGN, 3);
break;
}
align_x = GetStringRightAlignXOffset(0, strEV, total_x);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, strEV, align_x, base_y + base_y_offset*base_i);
base_i++;
//Egg cycles
if (sPokedexView->sPokemonStats.eggGroup1 == EGG_GROUP_NO_EGGS_DISCOVERED || sPokedexView->sPokemonStats.eggGroup2 == EGG_GROUP_NO_EGGS_DISCOVERED) //Species without eggs (legendaries etc)
{
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_EggCycles, base_x, base_y + base_y_offset*base_i);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gText_ThreeDashes, 78, base_y + base_y_offset*base_i);
}
else
{
PrintStatsScreenTextSmall(WIN_STATS_LEFT, sText_Stats_EggCycles, base_x, base_y + base_y_offset*base_i);
if (sPokedexView->sPokemonStats.eggCycles <= 10)
{
StringCopy(strEV, sText_Stats_EggCycles_VeryFast);
align_x = 76;
}
else if (sPokedexView->sPokemonStats.eggCycles <= 20)
{
StringCopy(strEV, sText_Stats_EggCycles_Fast);
align_x = 85;
}
else if (sPokedexView->sPokemonStats.eggCycles <= 30)
{
StringCopy(strEV, sText_Stats_EggCycles_Normal);
align_x = 76;
}
else
{
StringCopy(strEV, sText_Stats_EggCycles_Slow);
align_x = 67;
}
PrintStatsScreenTextSmall(WIN_STATS_LEFT, strEV, align_x, base_y + base_y_offset*base_i);
}
base_i++;
//Egg group 1
switch (sPokedexView->sPokemonStats.eggGroup1)
{
case EGG_GROUP_MONSTER:
StringCopy(gStringVar1, sText_Stats_eggGroup_MONSTER);
break;
case EGG_GROUP_WATER_1:
StringCopy(gStringVar1, sText_Stats_eggGroup_WATER_1);
break;
case EGG_GROUP_BUG:
StringCopy(gStringVar1, sText_Stats_eggGroup_BUG);
break;
case EGG_GROUP_FLYING:
StringCopy(gStringVar1, sText_Stats_eggGroup_FLYING);
break;
case EGG_GROUP_FIELD:
StringCopy(gStringVar1, sText_Stats_eggGroup_FIELD);
break;
case EGG_GROUP_FAIRY:
StringCopy(gStringVar1, sText_Stats_eggGroup_FAIRY);
break;
case EGG_GROUP_GRASS:
StringCopy(gStringVar1, sText_Stats_eggGroup_GRASS);
break;
case EGG_GROUP_HUMAN_LIKE:
StringCopy(gStringVar1, sText_Stats_eggGroup_HUMAN_LIKE);
break;
case EGG_GROUP_WATER_3:
StringCopy(gStringVar1, sText_Stats_eggGroup_WATER_3);
break;
case EGG_GROUP_MINERAL:
StringCopy(gStringVar1, sText_Stats_eggGroup_MINERAL);
break;
case EGG_GROUP_AMORPHOUS:
StringCopy(gStringVar1, sText_Stats_eggGroup_AMORPHOUS);
break;
case EGG_GROUP_WATER_2:
StringCopy(gStringVar1, sText_Stats_eggGroup_WATER_2);
break;
case EGG_GROUP_DITTO:
StringCopy(gStringVar1, sText_Stats_eggGroup_DITTO);
break;
case EGG_GROUP_DRAGON:
StringCopy(gStringVar1, sText_Stats_eggGroup_DRAGON);
break;
case EGG_GROUP_NO_EGGS_DISCOVERED:
StringCopy(gStringVar1, sText_Stats_eggGroup_NO_EGGS_DISCOVERED);
break;
default:
StringCopy(gStringVar1, sText_Stats_eggGroup_UNKNOWN);
break;
}
//Egg group 2
if (sPokedexView->sPokemonStats.eggGroup1 != sPokedexView->sPokemonStats.eggGroup2)
{
switch (sPokedexView->sPokemonStats.eggGroup2)
{
case EGG_GROUP_MONSTER:
StringCopy(gStringVar2, sText_Stats_eggGroup_MONSTER);
break;
case EGG_GROUP_WATER_1:
StringCopy(gStringVar2, sText_Stats_eggGroup_WATER_1);
break;
case EGG_GROUP_BUG:
StringCopy(gStringVar2, sText_Stats_eggGroup_BUG);
break;
case EGG_GROUP_FLYING:
StringCopy(gStringVar2, sText_Stats_eggGroup_FLYING);
break;
case EGG_GROUP_FIELD:
StringCopy(gStringVar2, sText_Stats_eggGroup_FIELD);
break;
case EGG_GROUP_FAIRY:
StringCopy(gStringVar2, sText_Stats_eggGroup_FAIRY);
break;
case EGG_GROUP_GRASS:
StringCopy(gStringVar2, sText_Stats_eggGroup_GRASS);
break;
case EGG_GROUP_HUMAN_LIKE:
StringCopy(gStringVar2, sText_Stats_eggGroup_HUMAN_LIKE);
break;
case EGG_GROUP_WATER_3:
StringCopy(gStringVar2, sText_Stats_eggGroup_WATER_3);
break;
case EGG_GROUP_MINERAL:
StringCopy(gStringVar2, sText_Stats_eggGroup_MINERAL);
break;
case EGG_GROUP_AMORPHOUS:
StringCopy(gStringVar2, sText_Stats_eggGroup_AMORPHOUS);
break;
case EGG_GROUP_WATER_2:
StringCopy(gStringVar2, sText_Stats_eggGroup_WATER_2);
break;
case EGG_GROUP_DITTO:
StringCopy(gStringVar2, sText_Stats_eggGroup_DITTO);
break;
case EGG_GROUP_DRAGON:
StringCopy(gStringVar2, sText_Stats_eggGroup_DRAGON);
break;
case EGG_GROUP_NO_EGGS_DISCOVERED:
StringCopy(gStringVar2, sText_Stats_eggGroup_NO_EGGS_DISCOVERED);
break;
default:
StringCopy(gStringVar2, sText_Stats_eggGroup_UNKNOWN);
break;
}
StringExpandPlaceholders(gStringVar3, sText_Stats_eggGroup_Groups);
align_x = GetStringRightAlignXOffset(0, gStringVar3, total_x);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar3, base_x, base_y + base_y_offset*base_i);
}
else
{
align_x = GetStringRightAlignXOffset(0, gStringVar1, total_x);
PrintStatsScreenTextSmall(WIN_STATS_LEFT, gStringVar1, base_x, base_y + base_y_offset*base_i);
}
base_i++;
}
}
static void PrintStatsScreen_Abilities(u8 taskId)
{
u8 abilities_x = 5;
u8 abilities_y = 3;
u16 ability0;
u16 ability1;
u16 abilityHidden;
//Abilitie(s)
if (gTasks[taskId].data[5] == 0)
{
ability0 = sPokedexView->sPokemonStats.ability0;
PrintStatsScreenTextSmallWhite(WIN_STATS_ABILITIES, gAbilitiesInfo[ability0].name, abilities_x, abilities_y);
PrintStatsScreenTextSmall(WIN_STATS_ABILITIES, gAbilitiesInfo[ability0].description, abilities_x, abilities_y + 14);
ability1 = sPokedexView->sPokemonStats.ability1;
if (ability1 != ABILITY_NONE && ability1 != ability0)
{
PrintStatsScreenTextSmallWhite(WIN_STATS_ABILITIES, gAbilitiesInfo[ability1].name, abilities_x, abilities_y + 30);
PrintStatsScreenTextSmall(WIN_STATS_ABILITIES, gAbilitiesInfo[ability1].description, abilities_x, abilities_y + 44);
}
}
else //Hidden abilities
{
abilityHidden = sPokedexView->sPokemonStats.abilityHidden;
PrintStatsScreenTextSmallWhite(WIN_STATS_ABILITIES, gAbilitiesInfo[abilityHidden].name, abilities_x, abilities_y);
PrintStatsScreenTextSmall(WIN_STATS_ABILITIES, gAbilitiesInfo[abilityHidden].description, abilities_x, abilities_y + 14);
}
}
static void Task_SwitchScreensFromStatsScreen(u8 taskId)
{
if (!gPaletteFade.active)
{
FreeSpriteTilesByTag(ITEM_TAG); //Destroy item icon
FreeSpritePaletteByTag(ITEM_TAG); //Destroy item icon
FreeSpriteOamMatrix(&gSprites[gTasks[taskId].data[3]]); //Destroy item icon
DestroySprite(&gSprites[gTasks[taskId].data[3]]); //Destroy item icon
FreeMonIconPalettes(); //Destroy pokemon icon sprite
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4]]); //Destroy pokemon icon sprite
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
switch (sPokedexView->screenSwitchState)
{
case 1:
FreeAllWindowBuffers();
InitWindows(sInfoScreen_WindowTemplates);
gTasks[taskId].func = Task_LoadAreaScreen;
break;
case 2:
gTasks[taskId].func = Task_LoadCryScreen;
break;
case 3:
FreeAllWindowBuffers();
InitWindows(sInfoScreen_WindowTemplates);
gTasks[taskId].func = Task_LoadEvolutionScreen;
break;
default:
gTasks[taskId].func = Task_LoadInfoScreen;
break;
}
}
}
static void Task_ExitStatsScreen(u8 taskId)
{
if (!gPaletteFade.active)
{
FreeSpriteTilesByTag(ITEM_TAG); //Destroy item icon
FreeSpritePaletteByTag(ITEM_TAG); //Destroy item icon
FreeSpriteOamMatrix(&gSprites[gTasks[taskId].data[3]]); //Destroy item icon
DestroySprite(&gSprites[gTasks[taskId].data[3]]); //Destroy item icon
FreeMonIconPalettes(); //Destroy pokemon icon sprite
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4]]); //Destroy pokemon icon sprite
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
FreeInfoScreenWindowAndBgBuffers();
DestroyTask(taskId);
}
}
//************************************
//* *
//* EVOS *
//* *
//************************************
static const u8 sEvoFormsPageNavigationTextColor[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY};
static void EvoFormsPage_PrintNavigationButtons(void)
{
u8 x = 6;
u8 y = 0;
FillWindowPixelBuffer(WIN_NAVIGATION_BUTTONS, PIXEL_FILL(0));
if (sPokedexView->selectedScreen == EVO_SCREEN)
{
if (!HGSS_DECAPPED)
AddTextPrinterParameterized3(WIN_NAVIGATION_BUTTONS, 0, x+9, y, sStatsPageNavigationTextColor, 0, sText_EVO_Buttons_PE);
else
AddTextPrinterParameterized3(WIN_NAVIGATION_BUTTONS, 0, x+9, y, sStatsPageNavigationTextColor, 0, sText_EVO_Buttons_Decapped_PE);
}
else if (sPokedexView->selectedScreen == FORMS_SCREEN)
{
if (sPokedexView->sFormScreenData.inSubmenu)
{
if (!HGSS_DECAPPED)
AddTextPrinterParameterized3(WIN_NAVIGATION_BUTTONS, 0, x, y, sStatsPageNavigationTextColor, 0, sText_FORMS_Buttons_Submenu_PE);
else
AddTextPrinterParameterized3(WIN_NAVIGATION_BUTTONS, 0, x, y, sStatsPageNavigationTextColor, 0, sText_FORMS_Buttons_Submenu_Decapped_PE);
}
else
{
if (!HGSS_DECAPPED)
AddTextPrinterParameterized3(WIN_NAVIGATION_BUTTONS, 0, x, y, sStatsPageNavigationTextColor, 0, sText_FORMS_Buttons_PE);
else
AddTextPrinterParameterized3(WIN_NAVIGATION_BUTTONS, 0, x, y, sStatsPageNavigationTextColor, 0, sText_FORMS_Buttons_Decapped_PE);
}
}
PutWindowTilemap(WIN_NAVIGATION_BUTTONS);
CopyWindowToVram(WIN_NAVIGATION_BUTTONS, COPYWIN_FULL);
}
static void ResetEvoScreenDataStruct(void)
{
u8 i;
sPokedexView->sEvoScreenData.numAllEvolutions = 0;
sPokedexView->sEvoScreenData.numSeen = 0;
sPokedexView->sEvoScreenData.menuPos = 0;
for (i = 0; i < 10; i++)
{
sPokedexView->sEvoScreenData.targetSpecies[i] = 0;
sPokedexView->sEvoScreenData.seen[i] = 0;
}
}
static void GetSeenFlagTargetSpecies(void)
{
u8 i;
u16 species;
for (i = 0; i < sPokedexView->sEvoScreenData.numAllEvolutions; i++)
{
species = sPokedexView->sEvoScreenData.targetSpecies[i];
if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_SEEN))
{
sPokedexView->sEvoScreenData.seen[i] = TRUE;
sPokedexView->sEvoScreenData.numSeen += 1;
}
}
}
static void Task_LoadEvolutionScreen(u8 taskId)
{
switch (gMain.state)
{
case 0:
default:
if (!gPaletteFade.active)
{
u16 r2;
sPokedexView->currentPage = EVO_SCREEN;
gPokedexVBlankCB = gMain.vblankCallback;
SetVBlankCallback(NULL);
r2 = 0;
if (gTasks[taskId].data[1] != 0)
r2 += DISPCNT_OBJ_ON;
if (gTasks[taskId].data[2] != 0)
r2 |= DISPCNT_BG1_ON;
ResetOtherVideoRegisters(r2);
gMain.state = 1;
}
break;
case 1:
LoadTilesetTilemapHGSS(EVO_SCREEN);
FillWindowPixelBuffer(WIN_INFO, PIXEL_FILL(0));
PutWindowTilemap(WIN_INFO);
CopyWindowToVram(WIN_INFO, COPYWIN_FULL);
FillWindowPixelBuffer(WIN_NAVIGATION_BUTTONS, PIXEL_FILL(0));
PutWindowTilemap(WIN_NAVIGATION_BUTTONS);
CopyWindowToVram(WIN_NAVIGATION_BUTTONS, COPYWIN_FULL);
CopyBgTilemapBufferToVram(1);
CopyBgTilemapBufferToVram(2);
CopyBgTilemapBufferToVram(3);
gMain.state++;
break;
case 2:
LoadScreenSelectBarMain(0xD);
LoadPokedexBgPalette(sPokedexView->isSearchResults);
gMain.state++;
break;
case 3:
if (gTasks[taskId].data[1] == 0)
{
u32 species = NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum);
u32 personality = GetPokedexMonPersonality(species);
sPokedexView->selectedScreen = EVO_SCREEN;
ResetEvoScreenDataStruct();
//Icon
FreeMonIconPalettes(); //Free space for new pallete
LoadMonIconPalettePersonality(species, personality); //Loads pallete for current mon
PrintPreEvolutions(taskId, species);
gTasks[taskId].data[4] = CreateMonIcon(species, SpriteCB_MonIcon, 18 + 32*sPokedexView->numPreEvolutions, 31, 4, personality); //Create pokemon sprite
EvoFormsPage_PrintNavigationButtons(); // Navigation buttons
gSprites[gTasks[taskId].data[4]].oam.priority = 0;
}
gMain.state++;
break;
case 4:
{
u32 alreadyPrintedIcons[MAX_EVOLUTION_ICONS] = {0};
u32 depth = sPokedexView->numPreEvolutions;
u32 iconDepth = depth;
//Print evo info and icons
gTasks[taskId].data[3] = 0;
PrintEvolutionTargetSpeciesAndMethod(taskId, NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum), 0, &depth, alreadyPrintedIcons, &iconDepth);
LoadSpritePalette(&gSpritePalette_Arrow);
GetSeenFlagTargetSpecies();
if (sPokedexView->sEvoScreenData.numAllEvolutions > 0 && sPokedexView->sEvoScreenData.numSeen > 0)
{
u32 pos;
for (pos = 0; !sPokedexView->sEvoScreenData.seen[pos]; pos++)
;
sPokedexView->sEvoScreenData.menuPos = pos;
sPokedexView->sEvoScreenData.arrowSpriteId = CreateSprite(&gSpriteTemplate_Arrow, 7, 58 + 9 * pos, 0);
gSprites[sPokedexView->sEvoScreenData.arrowSpriteId].animNum = 2;
}
gMain.state++;
break;
}
case 5:
{
u32 preservedPalettes = 0;
if (gTasks[taskId].data[2] != 0)
preservedPalettes = 0x14; // each bit represents a palette index
if (gTasks[taskId].data[1] != 0)
preservedPalettes |= (1 << (gSprites[gTasks[taskId].tMonSpriteId].oam.paletteNum + 16));
BeginNormalPaletteFade(~preservedPalettes, 0, 16, 0, RGB_BLACK);
SetVBlankCallback(gPokedexVBlankCB);
gMain.state++;
break;
}
case 6:
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
HideBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 7:
if (!gPaletteFade.active)
gMain.state++;
break;
case 8:
gMain.state++;
break;
case 9:
sPokedexView->screenSwitchState = 0;
gTasks[taskId].data[0] = 0;
gTasks[taskId].data[1] = 0;
gTasks[taskId].data[2] = 1;
gTasks[taskId].func = Task_HandleEvolutionScreenInput;
gMain.state = 0;
break;
}
}
static void Task_HandleEvolutionScreenInput(u8 taskId)
{
//Switch to forms screen, Pokemon Expansion only (rhh)
if (JOY_NEW(START_BUTTON))
{
sPokedexView->selectedScreen = FORMS_SCREEN;
BeginNormalPaletteFade(0xFFFFFFEB, 0, 0, 0x10, RGB_BLACK);
sPokedexView->screenSwitchState = 3;
gTasks[taskId].func = Task_SwitchScreensFromEvolutionScreen;
PlaySE(SE_PIN);
}
if (sPokedexView->sEvoScreenData.numAllEvolutions > 0 && sPokedexView->sEvoScreenData.numSeen > 0)
{
u8 base_y = 58;
u8 base_y_offset = 9;
u8 pos = sPokedexView->sEvoScreenData.menuPos;
u8 max = sPokedexView->sEvoScreenData.numAllEvolutions - 1;
if (JOY_NEW(DPAD_DOWN))
{
do
{
if (pos < max)
pos++;
else
pos = 0;
} while (!sPokedexView->sEvoScreenData.seen[pos]);
gSprites[sPokedexView->sEvoScreenData.arrowSpriteId].y = base_y + base_y_offset * pos;
sPokedexView->sEvoScreenData.menuPos = pos;
}
else if (JOY_NEW(DPAD_UP))
{
do
{
if (pos > 0)
pos--;
else
pos = max;
} while (!sPokedexView->sEvoScreenData.seen[pos]);
gSprites[sPokedexView->sEvoScreenData.arrowSpriteId].y = base_y + base_y_offset * pos;
sPokedexView->sEvoScreenData.menuPos = pos;
}
if (JOY_NEW(A_BUTTON))
{
u16 targetSpecies = sPokedexView->sEvoScreenData.targetSpecies[sPokedexView->sEvoScreenData.menuPos];
u16 dexNum = SpeciesToNationalPokedexNum(targetSpecies);
if (sPokedexView->isSearchResults && sPokedexView->originalSearchSelectionNum == 0)
sPokedexView->originalSearchSelectionNum = sPokedexListItem->dexNum;
sPokedexListItem->dexNum = dexNum;
sPokedexListItem->seen = GetSetPokedexFlag(dexNum, FLAG_GET_SEEN);
sPokedexListItem->owned = GetSetPokedexFlag(dexNum, FLAG_GET_CAUGHT);
if (GetSpeciesFormTable(targetSpecies) != NULL)
sPokedexView->formSpecies = targetSpecies;
else
sPokedexView->formSpecies = 0;
sPokedexView->sEvoScreenData.fromEvoPage = TRUE;
PlaySE(SE_PIN);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
gTasks[taskId].func = Task_LoadInfoScreenWaitForFade;
}
}
//Exit to overview
if (JOY_NEW(B_BUTTON))
{
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK);
gTasks[taskId].func = Task_ExitEvolutionScreen;
PlaySE(SE_PC_OFF);
return;
}
//Switch screens
if ((JOY_NEW(DPAD_LEFT) || (JOY_NEW(L_BUTTON) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_LR)))
{
sPokedexView->selectedScreen = STATS_SCREEN;
BeginNormalPaletteFade(0xFFFFFFEB, 0, 0, 0x10, RGB_BLACK);
sPokedexView->screenSwitchState = 1;
gTasks[taskId].func = Task_SwitchScreensFromEvolutionScreen;
PlaySE(SE_PIN);
}
if ((JOY_NEW(DPAD_RIGHT) || (JOY_NEW(R_BUTTON) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_LR)))
{
if (!sPokedexListItem->owned)
PlaySE(SE_FAILURE);
else
{
sPokedexView->selectedScreen = CRY_SCREEN;
BeginNormalPaletteFade(0xFFFFFFEB, 0, 0, 0x10, RGB_BLACK);
sPokedexView->screenSwitchState = 2;
gTasks[taskId].func = Task_SwitchScreensFromEvolutionScreen;
PlaySE(SE_PIN);
}
}
}
static void HandleTargetSpeciesPrintText(u32 targetSpecies, u32 base_x, u32 base_y, u32 base_y_offset, u32 base_i)
{
bool32 seen = GetSetPokedexFlag(SpeciesToNationalPokedexNum(targetSpecies), FLAG_GET_SEEN);
if (seen || !HGSS_HIDE_UNSEEN_EVOLUTION_NAMES)
StringCopy(gStringVar3, GetSpeciesName(targetSpecies)); //evolution mon name
else
StringCopy(gStringVar3, gText_ThreeQuestionMarks); //show questionmarks instead of name
StringExpandPlaceholders(gStringVar3, sText_EVO_Name); //evolution mon name
PrintInfoScreenTextSmall(gStringVar3, base_x, base_y + base_y_offset*base_i); //evolution mon name
}
static void HandleTargetSpeciesPrintIcon(u8 taskId, u16 targetSpecies, u8 base_i, u8 iterations)
{
u32 personality = GetPokedexMonPersonality(targetSpecies);
LoadMonIconPalettePersonality(targetSpecies, personality); //Loads pallete for current mon
if (iterations > 6) // Print icons closer to each other if there are many evolutions
gTasks[taskId].data[4+base_i] = CreateMonIcon(targetSpecies, SpriteCB_MonIcon, 45 + 26*base_i, 31, 4, personality);
else
gTasks[taskId].data[4+base_i] = CreateMonIcon(targetSpecies, SpriteCB_MonIcon, 50 + 32*base_i, 31, 4, personality);
gSprites[gTasks[taskId].data[4+base_i]].oam.priority = 0;
}
static void CreateCaughtBallEvolutionScreen(u16 targetSpecies, u8 x, u8 y, u16 unused)
{
bool8 owned = GetSetPokedexFlag(SpeciesToNationalPokedexNum(targetSpecies), FLAG_GET_CAUGHT);
if (owned)
BlitBitmapToWindow(0, sCaughtBall_Gfx, x, y-1, 8, 16);
else
{
//FillWindowPixelRect(0, PIXEL_FILL(0), x, y, 8, 16); //not sure why this was even here
PrintInfoScreenTextSmall(gText_OneDash, x+1, y-1);
}
}
static void HandlePreEvolutionSpeciesPrint(u8 taskId, u16 preSpecies, u16 species, u8 base_x, u8 base_y, u8 base_y_offset, u8 base_i)
{
bool8 seen = GetSetPokedexFlag(SpeciesToNationalPokedexNum(preSpecies), FLAG_GET_SEEN);
StringCopy(gStringVar1, GetSpeciesName(species)); //evolution mon name
if (sPokedexView->sEvoScreenData.isMega)
StringExpandPlaceholders(gStringVar3, sText_EVO_PreEvo_PE_Mega);
else
{
if (seen || !HGSS_HIDE_UNSEEN_EVOLUTION_NAMES)
StringCopy(gStringVar2, GetSpeciesName(preSpecies)); //evolution mon name
else
StringCopy(gStringVar2, gText_ThreeQuestionMarks); //show questionmarks instead of name
StringExpandPlaceholders(gStringVar3, sText_EVO_PreEvo); //evolution mon name
}
PrintInfoScreenTextSmall(gStringVar3, base_x, base_y + base_y_offset*base_i); //evolution mon name
if (base_i < 3)
{
u32 personality = GetPokedexMonPersonality(preSpecies);
LoadMonIconPalettePersonality(preSpecies, personality); //Loads pallete for current mon
gTasks[taskId].data[4+base_i] = CreateMonIcon(preSpecies, SpriteCB_MonIcon, 18 + 32*base_i, 31, 4, personality); //Create pokemon sprite
gSprites[gTasks[taskId].data[4+base_i]].oam.priority = 0;
}
}
static u8 PrintPreEvolutions(u8 taskId, u16 species)
{
u16 i;
u16 j;
u8 base_x = 13+8;
u8 base_y = 51;
u8 base_y_offset = 9;
u16 preEvolutionOne = 0;
u16 preEvolutionTwo = 0;
u8 numPreEvolutions = 0;
u16 baseFormSpecies;
sPokedexView->sEvoScreenData.isMega = FALSE;
//Check if it's a mega
baseFormSpecies = GetFormSpeciesId(species, 0);
if (baseFormSpecies != species)
{
const struct FormChange *formChanges = GetSpeciesFormChanges(baseFormSpecies);
for (i = 0; formChanges != NULL && formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
{
if (formChanges[i].method == FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM
&& formChanges[i].targetSpecies == species)
{
preEvolutionOne = baseFormSpecies;
numPreEvolutions += 1;
sPokedexView->numPreEvolutions = numPreEvolutions;
sPokedexView->sEvoScreenData.numAllEvolutions += numPreEvolutions;
sPokedexView->sEvoScreenData.isMega = TRUE;
CopyItemName(GetSpeciesFormChanges(species)->param1, gStringVar2); //item
CreateCaughtBallEvolutionScreen(preEvolutionOne, base_x - 9 - 8, base_y + base_y_offset*(numPreEvolutions - 1), 0);
HandlePreEvolutionSpeciesPrint(taskId, preEvolutionOne, species, base_x - 8, base_y, base_y_offset, numPreEvolutions - 1);
return numPreEvolutions;
}
}
}
//Calculate previous evolution
for (i = 0; i < NUM_SPECIES; i++)
{
const struct Evolution *evolutions = GetSpeciesEvolutions(i);
if (evolutions == NULL)
continue;
for (j = 0; evolutions[j].method != EVOLUTIONS_END; j++)
{
if (evolutions[j].targetSpecies == species)
{
preEvolutionOne = i;
numPreEvolutions += 1;
break;
}
}
}
//Calculate if previous evolution also has a previous evolution
if (numPreEvolutions != 0)
{
for (i = 0; i < NUM_SPECIES; i++)
{
const struct Evolution *evolutions = GetSpeciesEvolutions(i);
if (evolutions == NULL)
continue;
for (j = 0; evolutions[j].method != EVOLUTIONS_END; j++)
{
if (evolutions[j].targetSpecies == preEvolutionOne)
{
preEvolutionTwo = i;
numPreEvolutions += 1;
CreateCaughtBallEvolutionScreen(preEvolutionTwo, base_x - 9, base_y + base_y_offset*0, 0);
HandlePreEvolutionSpeciesPrint(taskId, preEvolutionTwo, preEvolutionOne, base_x, base_y, base_y_offset, 0);
break;
}
}
}
}
//Print ball and name
if (preEvolutionOne != 0)
{
CreateCaughtBallEvolutionScreen(preEvolutionOne, base_x - 9, base_y + base_y_offset*(numPreEvolutions - 1), 0);
HandlePreEvolutionSpeciesPrint(taskId, preEvolutionOne, species, base_x, base_y, base_y_offset, numPreEvolutions - 1);
}
if (preEvolutionTwo != 0)
{
sPokedexView->sEvoScreenData.targetSpecies[0] = preEvolutionTwo;
sPokedexView->sEvoScreenData.targetSpecies[1] = preEvolutionOne;
}
else if (preEvolutionOne != 0)
{
sPokedexView->sEvoScreenData.targetSpecies[0] = preEvolutionOne;
}
//vertical line
//FillWindowPixelRect(0, PIXEL_FILL(5), 33 + 32*numPreEvolutions, 18, 1, 32); //PIXEL_FILL(15) for black
sPokedexView->numPreEvolutions = numPreEvolutions;
sPokedexView->sEvoScreenData.numAllEvolutions += numPreEvolutions;
return numPreEvolutions;
}
#define EVO_SCREEN_LVL_DIGITS 2
#define EVO_SCREEN_CRITS_DIGITS 1
#define EVO_SCREEN_DMG_DIGITS 2
static void PrintEvolutionTargetSpeciesAndMethod(u8 taskId, u16 species, u8 depth, u32 *depth_i, u32 alreadyPrintedIcons[], u32 *icon_depth_i)
{
int i;
const struct MapHeader *mapHeader;
u16 targetSpecies = 0;
u16 item;
bool8 left = TRUE;
u8 base_x = 13+8;
u8 base_x_offset = 54+8;
u8 base_y = 51;
u8 base_y_offset = 9;
u8 times = 0;
u8 depth_x = 16;
const struct Evolution *evolutions = GetSpeciesEvolutions(species);
if (sPokedexView->sEvoScreenData.isMega)
return;
StringCopy(gStringVar1, GetSpeciesName(species));
//If there are no evolutions print text and return
if (evolutions == NULL)
{
if (depth == 0)
{
StringExpandPlaceholders(gStringVar4, sText_EVO_NONE);
PrintInfoScreenTextSmall(gStringVar4, base_x-7-7, base_y + base_y_offset*(*depth_i));
}
return;
}
//Calculate number of possible direct evolutions (e.g. Eevee has 5 but torchic has 1)
for (i = 0; evolutions[i].method != EVOLUTIONS_END; i++)
{
if (evolutions[i].method != 0)
times += 1;
}
gTasks[taskId].data[3] = times;
sPokedexView->sEvoScreenData.numAllEvolutions += times;
//If there are evolutions find out which and print them 1 by 1
for (i = 0; i < times; i++)
{
int j;
left = !left;
targetSpecies = evolutions[i].targetSpecies;
sPokedexView->sEvoScreenData.targetSpecies[*depth_i] = targetSpecies;
CreateCaughtBallEvolutionScreen(targetSpecies, base_x + depth_x*depth-9, base_y + base_y_offset*(*depth_i), 0);
HandleTargetSpeciesPrintText(targetSpecies, base_x + depth_x*depth, base_y, base_y_offset, *depth_i); //evolution mon name
for (j = 0; j < MAX_EVOLUTION_ICONS; j++)
{
if (alreadyPrintedIcons[j] == targetSpecies)
break;
if (alreadyPrintedIcons[j] == SPECIES_NONE)
{
HandleTargetSpeciesPrintIcon(taskId, targetSpecies, *icon_depth_i, times);
alreadyPrintedIcons[j] = targetSpecies;
(*icon_depth_i)++;
break;
}
}
switch (evolutions[i].method)
{
case EVO_FRIENDSHIP:
ConvertIntToDecimalStringN(gStringVar2, 220, STR_CONV_MODE_LEADING_ZEROS, 3); //friendship value
StringExpandPlaceholders(gStringVar4, sText_EVO_FRIENDSHIP );
break;
case EVO_FRIENDSHIP_DAY:
StringExpandPlaceholders(gStringVar4, sText_EVO_FRIENDSHIP_DAY );
break;
case EVO_FRIENDSHIP_NIGHT:
StringExpandPlaceholders(gStringVar4, sText_EVO_FRIENDSHIP_NIGHT );
break;
case EVO_LEVEL:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL );
break;
case EVO_TRADE:
StringExpandPlaceholders(gStringVar4, sText_EVO_TRADE );
break;
case EVO_TRADE_ITEM:
item = evolutions[i].param; //item
CopyItemName(item, gStringVar2); //item
StringExpandPlaceholders(gStringVar4, sText_EVO_TRADE_ITEM );
break;
case EVO_ITEM:
item = evolutions[i].param;
CopyItemName(item, gStringVar2);
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM );
break;
case EVO_LEVEL_ATK_GT_DEF:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_ATK_GT_DEF );
break;
case EVO_LEVEL_ATK_EQ_DEF:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_ATK_EQ_DEF );
break;
case EVO_LEVEL_ATK_LT_DEF:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_ATK_LT_DEF );
break;
case EVO_LEVEL_SILCOON:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_SILCOON );
break;
case EVO_LEVEL_CASCOON:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_CASCOON );
break;
case EVO_LEVEL_NINJASK:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_NINJASK );
break;
case EVO_LEVEL_SHEDINJA:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_SHEDINJA );
break;
case EVO_BEAUTY:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, 3); //beauty
StringExpandPlaceholders(gStringVar4, sText_EVO_BEAUTY );
break;
case EVO_LEVEL_FEMALE:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_FEMALE );
break;
case EVO_LEVEL_MALE:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_MALE );
break;
case EVO_LEVEL_NIGHT:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_NIGHT );
break;
case EVO_LEVEL_DAY:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_DAY );
break;
case EVO_LEVEL_DUSK:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_DUSK );
break;
case EVO_ITEM_HOLD_DAY:
item = evolutions[i].param; //item
CopyItemName(item, gStringVar2); //item
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM_HOLD_DAY );
break;
case EVO_ITEM_HOLD_NIGHT:
item = evolutions[i].param; //item
CopyItemName(item, gStringVar2); //item
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM_HOLD_NIGHT );
break;
case EVO_MOVE:
StringCopy(gStringVar2, GetMoveName(evolutions[i].param));
StringExpandPlaceholders(gStringVar4, sText_EVO_MOVE );
break;
case EVO_FRIENDSHIP_MOVE_TYPE:
StringCopy(gStringVar2, gTypesInfo[evolutions[i].param].name);
StringExpandPlaceholders(gStringVar4, sText_EVO_FRIENDSHIP_MOVE_TYPE );
break;
case EVO_MAPSEC:
StringCopy(gStringVar2, gRegionMapEntries[evolutions[i].param].name);
StringExpandPlaceholders(gStringVar4, sText_EVO_MAPSEC );
break;
case EVO_ITEM_MALE:
item = evolutions[i].param; //item
CopyItemName(item, gStringVar2); //item
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM_MALE );
break;
case EVO_ITEM_FEMALE:
item = evolutions[i].param; //item
CopyItemName(item, gStringVar2); //item
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM_FEMALE );
break;
case EVO_LEVEL_RAIN:
//if (j == WEATHER_RAIN || j == WEATHER_RAIN_THUNDERSTORM || j == WEATHER_DOWNPOUR)
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_RAIN );
break;
case EVO_SPECIFIC_MON_IN_PARTY:
StringCopy(gStringVar2, GetSpeciesName(evolutions[i].param)); //mon name
StringExpandPlaceholders(gStringVar4, sText_EVO_SPECIFIC_MON_IN_PARTY );
break;
case EVO_LEVEL_DARK_TYPE_MON_IN_PARTY:
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_DARK_TYPE_MON_IN_PARTY );
break;
case EVO_TRADE_SPECIFIC_MON:
StringCopy(gStringVar2, GetSpeciesName(evolutions[i].param)); //mon name
StringExpandPlaceholders(gStringVar4, sText_EVO_TRADE_SPECIFIC_MON );
break;
case EVO_SPECIFIC_MAP:
mapHeader = Overworld_GetMapHeaderByGroupAndId(evolutions[i].param >> 8, evolutions[i].param & 0xFF);
GetMapName(gStringVar2, mapHeader->regionMapSectionId, 0);
StringExpandPlaceholders(gStringVar4, sText_EVO_SPECIFIC_MAP );
break;
case EVO_LEVEL_NATURE_AMPED:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_NATURE_AMPED);
break;
case EVO_LEVEL_NATURE_LOW_KEY:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_LVL_DIGITS); //level
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_NATURE_LOW_KEY);
break;
case EVO_CRITICAL_HITS:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_CRITS_DIGITS); //crits
StringExpandPlaceholders(gStringVar4, sText_EVO_CRITICAL_HITS);
break;
case EVO_SCRIPT_TRIGGER_DMG:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, EVO_SCREEN_DMG_DIGITS); //damage
StringExpandPlaceholders(gStringVar4, sText_EVO_SCRIPT_TRIGGER_DMG);
break;
case EVO_DARK_SCROLL:
item = evolutions[i].param;
CopyItemName(item, gStringVar2);
StringExpandPlaceholders(gStringVar4, sText_EVO_DARK_SCROLL );
break;
case EVO_WATER_SCROLL:
item = evolutions[i].param;
CopyItemName(item, gStringVar2);
StringExpandPlaceholders(gStringVar4, sText_EVO_WATER_SCROLL );
break;
case EVO_ITEM_NIGHT:
item = evolutions[i].param;
CopyItemName(item, gStringVar2);
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM_NIGHT );
break;
case EVO_ITEM_DAY:
item = evolutions[i].param;
CopyItemName(item, gStringVar2);
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM_DAY );
break;
case EVO_ITEM_HOLD:
item = evolutions[i].param;
CopyItemName(item, gStringVar2);
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM_HOLD );
break;
case EVO_USE_MOVE_TWENTY_TIMES:
StringCopy(gStringVar2, GetMoveName(evolutions[i].param));
StringExpandPlaceholders(gStringVar4, sText_EVO_USE_MOVE_TWENTY_TIMES );
break;
case EVO_RECOIL_DAMAGE_MALE:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, 3);
StringExpandPlaceholders(gStringVar4, sText_EVO_RECOIL_DAMAGE_MALE);
break;
case EVO_RECOIL_DAMAGE_FEMALE:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, 3);
StringExpandPlaceholders(gStringVar4, sText_EVO_RECOIL_DAMAGE_FEMALE);
break;
case EVO_ITEM_COUNT_999:
item = evolutions[i].param;
CopyItemName(item, gStringVar2);
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM_COUNT_999);
break;
case EVO_DEFEAT_THREE_WITH_ITEM:
item = evolutions[i].param;
CopyItemName(item, gStringVar2);
StringCopy(gStringVar3, GetSpeciesName(species));
StringExpandPlaceholders(gStringVar4, sText_EVO_DEFEAT_THREE_WITH_ITEM);
break;
case EVO_OVERWORLD_STEPS:
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, 4);
StringExpandPlaceholders(gStringVar4, sText_EVO_OVERWORLD_STEPS);
break;
default:
StringExpandPlaceholders(gStringVar4, sText_EVO_UNKNOWN);
break;
}//Switch end
PrintInfoScreenTextSmall(gStringVar4, base_x + depth_x*depth+base_x_offset, base_y + base_y_offset*(*depth_i)); //Print actual instructions
(*depth_i)++;
PrintEvolutionTargetSpeciesAndMethod(taskId, targetSpecies, depth+1, depth_i, alreadyPrintedIcons, icon_depth_i);
}//For loop end
}
static void Task_SwitchScreensFromEvolutionScreen(u8 taskId)
{
u8 i;
if (!gPaletteFade.active)
{
FreeMonIconPalettes(); //Destroy pokemon icon sprite
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4]]); //Destroy pokemon icon sprite
for (i = 1; i <= gTasks[taskId].data[3]; i++)
{
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4+i]]); //Destroy pokemon icon sprite
}
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
switch (sPokedexView->screenSwitchState)
{
case 1:
gTasks[taskId].func = Task_LoadStatsScreen;
break;
case 2:
gTasks[taskId].func = Task_LoadCryScreen;
break;
case 3:
gTasks[taskId].func = Task_LoadFormsScreen;
break;
default:
gTasks[taskId].func = Task_LoadInfoScreen;
break;
}
}
}
static void Task_ExitEvolutionScreen(u8 taskId)
{
u8 i;
if (!gPaletteFade.active)
{
FreeMonIconPalettes(); //Destroy pokemon icon sprite
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4]]); //Destroy pokemon icon sprite
for (i = 1; i <= gTasks[taskId].data[3]; i++)
{
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4+i]]); //Destroy pokemon icon sprite
}
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
FreeInfoScreenWindowAndBgBuffers();
DestroyTask(taskId);
}
}
//************************************
//* *
//* FORMS *
//* *
//************************************
static void Task_LoadFormsScreen(u8 taskId)
{
switch (gMain.state)
{
case 0:
default:
if (!gPaletteFade.active)
{
u16 r2;
sPokedexView->currentPage = FORMS_SCREEN;
gPokedexVBlankCB = gMain.vblankCallback;
SetVBlankCallback(NULL);
r2 = 0;
if (gTasks[taskId].data[1] != 0)
r2 += DISPCNT_OBJ_ON;
if (gTasks[taskId].data[2] != 0)
r2 |= DISPCNT_BG1_ON;
ResetOtherVideoRegisters(r2);
gMain.state = 1;
}
break;
case 1:
LoadTilesetTilemapHGSS(FORMS_SCREEN);
FillWindowPixelBuffer(WIN_INFO, PIXEL_FILL(0));
PutWindowTilemap(WIN_INFO);
CopyWindowToVram(WIN_INFO, COPYWIN_FULL);
FillWindowPixelBuffer(WIN_NAVIGATION_BUTTONS, PIXEL_FILL(0));
PutWindowTilemap(WIN_NAVIGATION_BUTTONS);
CopyWindowToVram(WIN_NAVIGATION_BUTTONS, COPYWIN_FULL);
CopyBgTilemapBufferToVram(1);
CopyBgTilemapBufferToVram(2);
CopyBgTilemapBufferToVram(3);
gMain.state++;
break;
case 2:
LoadScreenSelectBarMain(0xD);
LoadPokedexBgPalette(sPokedexView->isSearchResults);
gMain.state++;
break;
case 3:
if (gTasks[taskId].data[1] == 0)
{
//Icon
u32 species = NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum);
u32 personality = GetPokedexMonPersonality(species);
FreeMonIconPalettes(); //Free space for new pallete
LoadMonIconPalettePersonality(species, personality); //Loads pallete for current mon
gTasks[taskId].data[4] = CreateMonIcon(species, SpriteCB_MonIcon, 18, 31, 4, personality); //Create pokemon sprite
gSprites[gTasks[taskId].data[4]].oam.priority = 0;
}
EvoFormsPage_PrintNavigationButtons(); // Navigation buttons
sPokedexView->sFormScreenData.menuPos = 1;
gMain.state++;
break;
case 4:
//Print form icons
gTasks[taskId].data[3] = 0;
PrintForms(taskId, NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum));
LoadSpritePalette(&gSpritePalette_Arrow);
gMain.state++;
break;
case 5:
{
u32 preservedPalettes = 0;
if (gTasks[taskId].data[2] != 0)
preservedPalettes = 0x14; // each bit represents a palette index
if (gTasks[taskId].data[1] != 0)
preservedPalettes |= (1 << (gSprites[gTasks[taskId].tMonSpriteId].oam.paletteNum + 16));
BeginNormalPaletteFade(~preservedPalettes, 0, 16, 0, RGB_BLACK);
SetVBlankCallback(gPokedexVBlankCB);
gMain.state++;
break;
}
case 6:
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
HideBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 7:
if (!gPaletteFade.active)
gMain.state++;
break;
case 8:
gMain.state++;
break;
case 9:
sPokedexView->screenSwitchState = 0;
gTasks[taskId].data[0] = 0;
gTasks[taskId].data[1] = 0;
gTasks[taskId].data[2] = 1;
gTasks[taskId].func = Task_HandleFormsScreenInput;
gMain.state = 0;
break;
}
}
static void Task_HandleFormsScreenInput(u8 taskId)
{
u8 base_x = 5;
u8 base_y = 34;
u8 offset_x = 34;
u8 offset_y = 34;
if (!sPokedexView->sFormScreenData.inSubmenu)
{
if (JOY_NEW(A_BUTTON) && sPokedexView->sFormScreenData.numForms != 0)
{
sPokedexView->sFormScreenData.inSubmenu = TRUE;
sPokedexView->sFormScreenData.arrowSpriteId = CreateSprite(&gSpriteTemplate_Arrow, base_x + offset_x, base_y, 0);
gSprites[sPokedexView->sFormScreenData.arrowSpriteId].animNum = 2;
EvoFormsPage_PrintNavigationButtons();
}
if (JOY_NEW(START_BUTTON))
{
sPokedexView->selectedScreen = EVO_SCREEN;
BeginNormalPaletteFade(0xFFFFFFEB, 0, 0, 0x10, RGB_BLACK);
sPokedexView->screenSwitchState = 1;
gTasks[taskId].func = Task_SwitchScreensFromFormsScreen;
PlaySE(SE_PIN);
}
//Exit to overview
if (JOY_NEW(B_BUTTON))
{
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK);
gTasks[taskId].func = Task_ExitFormsScreen;
PlaySE(SE_PC_OFF);
return;
}
}
else //inSubmenu
{
u8 row = 0;
u8 column = 0;
u8 menuPos = sPokedexView->sFormScreenData.menuPos;
//Grid navigation
if (JOY_NEW(DPAD_RIGHT))
menuPos += 1;
else if (JOY_NEW(DPAD_LEFT))
menuPos -= 1;
else if (JOY_NEW(DPAD_DOWN))
menuPos += 7;
else if (JOY_NEW(DPAD_UP))
{
if (menuPos > 7)
menuPos -= 7;
else
menuPos = 1;
}
if (menuPos <= 0)
menuPos = 1;
else if (menuPos >= sPokedexView->sFormScreenData.numForms)
menuPos = sPokedexView->sFormScreenData.numForms;
row = menuPos / 7;
column = menuPos % 7;
gSprites[sPokedexView->sFormScreenData.arrowSpriteId].x = base_x + offset_x * column;
gSprites[sPokedexView->sFormScreenData.arrowSpriteId].y = base_y + offset_y * row;
sPokedexView->sFormScreenData.menuPos = menuPos;
if (JOY_NEW(A_BUTTON))
{
u8 formId = sPokedexView->sFormScreenData.formIds[menuPos];
u16 formSpecies = GetFormSpeciesId(NationalPokedexNumToSpecies(sPokedexListItem->dexNum), formId);
if (sPokedexView->isSearchResults && sPokedexView->originalSearchSelectionNum == 0)
sPokedexView->originalSearchSelectionNum = sPokedexListItem->dexNum;
if (formSpecies == GetFormSpeciesId(formSpecies, 0))
sPokedexView->formSpecies = 0;
else
sPokedexView->formSpecies = formSpecies;
sPokedexView->sEvoScreenData.fromEvoPage = TRUE;
sPokedexView->sFormScreenData.inSubmenu = FALSE;
PlaySE(SE_PIN);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
gTasks[taskId].func = Task_LoadInfoScreenWaitForFade;
}
if (JOY_NEW(B_BUTTON))
{
DestroySprite(&gSprites[sPokedexView->sFormScreenData.arrowSpriteId]);
sPokedexView->sFormScreenData.inSubmenu = FALSE;
EvoFormsPage_PrintNavigationButtons();
}
}
}
#define FORM_SPECIES_END (0xffff)
static void PrintForms(u8 taskId, u16 species)
{
u8 i;
u8 j = 1;
u16 speciesForm;
u8 base_x = 5;
u8 base_y = 52;
u8 base_y_offset = 9;
u8 times = 0;
u8 y_offset_icons = 0; //For unown only
if (species == SPECIES_UNOWN)
y_offset_icons = 8;
if (GetFormSpeciesId(species, 0) == SPECIES_UNOWN)
y_offset_icons = 8;
StringCopy(gStringVar1, GetSpeciesName(species));
for (i=0; i < 30; i++)
{
speciesForm = GetFormSpeciesId(species, i);
if (speciesForm == FORM_SPECIES_END)
break;
else if (speciesForm == species)
continue;
else
{
u32 personality = GetPokedexMonPersonality(speciesForm);
sPokedexView->sFormScreenData.formIds[j++] = i;
times += 1;
LoadMonIconPalettePersonality(speciesForm, personality); //Loads pallete for current mon
if (times < 7)
gTasks[taskId].data[4+times] = CreateMonIcon(speciesForm, SpriteCB_MonIcon, 52 + 34*(times-1), 31, 4, personality); //Create pokemon sprite
else if (times < 14)
gTasks[taskId].data[4+times] = CreateMonIcon(speciesForm, SpriteCB_MonIcon, 18 + 34*(times-7), 70 - y_offset_icons, 4, personality); //Create pokemon sprite
gSprites[gTasks[taskId].data[4+times]].oam.priority = 0;
}
}
gTasks[taskId].data[3] = times;
sPokedexView->sFormScreenData.numForms = times;
//If there are no forms print text
if (times == 0)
{
StringExpandPlaceholders(gStringVar4, sText_FORMS_NONE);
PrintInfoScreenTextSmall(gStringVar4, base_x, base_y + base_y_offset*times);
}
}
static void Task_SwitchScreensFromFormsScreen(u8 taskId)
{
u8 i;
if (!gPaletteFade.active)
{
FreeMonIconPalettes(); //Destroy pokemon icon sprite
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4]]); //Destroy pokemon icon sprite
for (i = 1; i <= gTasks[taskId].data[3]; i++)
{
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4+i]]); //Destroy pokemon icon sprite
}
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
switch (sPokedexView->screenSwitchState)
{
case 1:
gTasks[taskId].func = Task_LoadEvolutionScreen;
break;
default:
gTasks[taskId].func = Task_LoadInfoScreen;
break;
}
}
}
static void Task_ExitFormsScreen(u8 taskId)
{
u8 i;
if (!gPaletteFade.active)
{
FreeMonIconPalettes(); //Destroy pokemon icon sprite
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4]]); //Destroy pokemon icon sprite
for (i = 1; i <= gTasks[taskId].data[3]; i++)
{
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].data[4+i]]); //Destroy pokemon icon sprite
}
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
FreeInfoScreenWindowAndBgBuffers();
DestroyTask(taskId);
}
}
#undef tMonSpriteId
//************************************
//* *
//* Cry screen *
//* *
//************************************
#define tScrolling data[0]
#define tMonSpriteDone data[1]
#define tBgLoaded data[2]
#define tSkipCry data[3]
#define tMonSpriteId data[4]
#define tTrainerSpriteId data[5]
static void Task_LoadCryScreen(u8 taskId)
{
switch (gMain.state)
{
case 0:
default:
if (!gPaletteFade.active)
{
m4aMPlayStop(&gMPlayInfo_BGM);
sPokedexView->currentPage = PAGE_CRY;
gPokedexVBlankCB = gMain.vblankCallback;
SetVBlankCallback(NULL);
ResetOtherVideoRegisters(DISPCNT_BG1_ON);
sPokedexView->selectedScreen = CRY_SCREEN;
gMain.state = 1;
}
break;
case 1:
LoadTilesetTilemapHGSS(CRY_SCREEN);
FillWindowPixelBuffer(WIN_INFO, PIXEL_FILL(0));
PutWindowTilemap(WIN_INFO);
PutWindowTilemap(WIN_VU_METER);
PutWindowTilemap(WIN_CRY_WAVE);
gMain.state++;
break;
case 2:
LoadScreenSelectBarMain(0xD);
LoadPokedexBgPalette(sPokedexView->isSearchResults);
gMain.state++;
break;
case 3:
ResetPaletteFade();
gMain.state++;
break;
case 4:
PrintInfoScreenText(gText_CryOf, 82, 33);
PrintCryScreenSpeciesName(0, sPokedexListItem->dexNum, 82, 49);
gMain.state++;
break;
case 5:
gTasks[taskId].tMonSpriteId = CreateMonSpriteFromNationalDexNumberHGSS(sPokedexListItem->dexNum, MON_PAGE_X, MON_PAGE_Y, 0);
gSprites[gTasks[taskId].tMonSpriteId].oam.priority = 0;
gDexCryScreenState = 0;
gMain.state++;
break;
case 6:
{
struct CryScreenWindow waveformWindow;
waveformWindow.unk0 = 0x4020;
waveformWindow.unk2 = 31;
waveformWindow.paletteNo = 8;
waveformWindow.yPos = 30;
waveformWindow.xPos = 12;
if (LoadCryWaveformWindow(&waveformWindow, 2))
{
gMain.state++;
gDexCryScreenState = 0;
}
break;
}
case 7:
{
struct CryScreenWindow cryMeter;
cryMeter.paletteNo = 9;
cryMeter.xPos = 18;
cryMeter.yPos = 3;
if (LoadCryMeter(&cryMeter, 3))
gMain.state++;
CopyWindowToVram(WIN_VU_METER, COPYWIN_GFX);
CopyWindowToVram(WIN_INFO, COPYWIN_FULL);
CopyBgTilemapBufferToVram(0);
CopyBgTilemapBufferToVram(1);
CopyBgTilemapBufferToVram(2);
CopyBgTilemapBufferToVram(3);
break;
}
case 8:
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0x10, 0, RGB_BLACK);
SetVBlankCallback(gPokedexVBlankCB);
gMain.state++;
break;
case 9:
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
ShowBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 10:
sPokedexView->screenSwitchState = 0;
gMain.state = 0;
gTasks[taskId].func = Task_HandleCryScreenInput;
break;
}
}
static void Task_HandleCryScreenInput(u8 taskId)
{
UpdateCryWaveformWindow(2);
if (IsCryPlaying())
LoadPlayArrowPalette(TRUE);
else
LoadPlayArrowPalette(FALSE);
if (JOY_NEW(A_BUTTON))
{
LoadPlayArrowPalette(TRUE);
CryScreenPlayButton(NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum));
return;
}
else if (!gPaletteFade.active)
{
if (JOY_NEW(B_BUTTON))
{
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0, 0x10, RGB_BLACK);
m4aMPlayContinue(&gMPlayInfo_BGM);
sPokedexView->screenSwitchState = 1;
gTasks[taskId].func = Task_SwitchScreensFromCryScreen;
PlaySE(SE_PC_OFF);
return;
}
if (JOY_NEW(DPAD_LEFT)
|| (JOY_NEW(L_BUTTON) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_LR))
{
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0, 0x10, RGB_BLACK);
m4aMPlayContinue(&gMPlayInfo_BGM);
sPokedexView->screenSwitchState = 2;
gTasks[taskId].func = Task_SwitchScreensFromCryScreen;
PlaySE(SE_DEX_PAGE);
return;
}
if (JOY_NEW(DPAD_RIGHT)
|| (JOY_NEW(R_BUTTON) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_LR))
{
if (!sPokedexListItem->owned)
{
PlaySE(SE_FAILURE);
}
else
{
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0, 0x10, RGB_BLACK);
m4aMPlayContinue(&gMPlayInfo_BGM);
sPokedexView->screenSwitchState = 3;
gTasks[taskId].func = Task_SwitchScreensFromCryScreen;
PlaySE(SE_DEX_PAGE);
}
return;
}
}
}
static void Task_SwitchScreensFromCryScreen(u8 taskId)
{
if (!gPaletteFade.active)
{
FreeCryScreen();
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
switch (sPokedexView->screenSwitchState)
{
default:
case 1:
gTasks[taskId].func = Task_LoadInfoScreen;
break;
case 2:
gTasks[taskId].func = Task_LoadEvolutionScreen;
break;
case 3:
gTasks[taskId].func = Task_LoadSizeScreen;
break;
}
}
}
//************************************
//* *
//* Size screen *
//* *
//************************************
static void Task_LoadSizeScreen(u8 taskId)
{
u8 spriteId;
switch (gMain.state)
{
default:
case 0:
if (!gPaletteFade.active)
{
sPokedexView->currentPage = PAGE_SIZE;
gPokedexVBlankCB = gMain.vblankCallback;
SetVBlankCallback(NULL);
ResetOtherVideoRegisters(DISPCNT_BG1_ON);
sPokedexView->selectedScreen = SIZE_SCREEN;
gMain.state = 1;
}
break;
case 1:
LoadTilesetTilemapHGSS(SIZE_SCREEN);
FillWindowPixelBuffer(WIN_INFO, PIXEL_FILL(0));
PutWindowTilemap(WIN_INFO);
gMain.state++;
break;
case 2:
LoadScreenSelectBarMain(0xD);
LoadPokedexBgPalette(sPokedexView->isSearchResults);
gMain.state++;
break;
case 3:
{
u8 string[64];
StringCopy(string, gText_SizeComparedTo);
StringAppend(string, gSaveBlock2Ptr->playerName);
PrintInfoScreenText(string, GetStringCenterAlignXOffset(FONT_NORMAL, string, 0xF0), 0x79);
gMain.state++;
break;
}
case 4:
ResetPaletteFade();
gMain.state++;
break;
case 5:
spriteId = CreateSizeScreenTrainerPic(PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender), 152, 56, 0);
gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL;
gSprites[spriteId].oam.matrixNum = 1;
gSprites[spriteId].oam.priority = 0;
gSprites[spriteId].y2 = GetTrainerOffsetFromNationalDexNumber(sPokedexListItem->dexNum);
SetOamMatrix(1, GetTrainerScaleFromNationalDexNumber(sPokedexListItem->dexNum), 0, 0, GetTrainerScaleFromNationalDexNumber(sPokedexListItem->dexNum));
LoadPalette(sSizeScreenSilhouette_Pal, OBJ_PLTT_ID2(gSprites[spriteId].oam.paletteNum), PLTT_SIZE_4BPP);
gTasks[taskId].tTrainerSpriteId = spriteId;
gMain.state++;
break;
case 6:
spriteId = CreateMonSpriteFromNationalDexNumberHGSS(sPokedexListItem->dexNum, 88, 56, 1);
gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL;
gSprites[spriteId].oam.matrixNum = 2;
gSprites[spriteId].oam.priority = 0;
gSprites[spriteId].y2 = GetPokemonOffsetFromNationalDexNumber(sPokedexListItem->dexNum);
SetOamMatrix(2, GetPokemonScaleFromNationalDexNumber(sPokedexListItem->dexNum), 0, 0, GetPokemonScaleFromNationalDexNumber(sPokedexListItem->dexNum));
LoadPalette(sSizeScreenSilhouette_Pal, OBJ_PLTT_ID2(gSprites[spriteId].oam.paletteNum), PLTT_SIZE_4BPP);
gTasks[taskId].tMonSpriteId = spriteId;
CopyWindowToVram(WIN_INFO, COPYWIN_FULL);
CopyBgTilemapBufferToVram(1);
CopyBgTilemapBufferToVram(2);
CopyBgTilemapBufferToVram(3);
gMain.state++;
break;
case 7:
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0x10, 0, RGB_BLACK);
SetVBlankCallback(gPokedexVBlankCB);
gMain.state++;
break;
case 8:
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
HideBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 9:
if (!gPaletteFade.active)
{
sPokedexView->screenSwitchState = 0;
gMain.state = 0;
gTasks[taskId].func = Task_HandleSizeScreenInput;
}
break;
}
}
static void LoadPlayArrowPalette(bool8 cryPlaying)
{
u16 color;
if (cryPlaying)
color = RGB(18, 28, 0);
else
color = RGB(15, 21, 0);
LoadPalette(&color, BG_PLTT_ID(5) + 13, PLTT_SIZEOF(1));
}
static void Task_HandleSizeScreenInput(u8 taskId)
{
if (JOY_NEW(B_BUTTON))
{
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0, 0x10, RGB_BLACK);
sPokedexView->screenSwitchState = 1;
gTasks[taskId].func = Task_SwitchScreensFromSizeScreen;
PlaySE(SE_PC_OFF);
}
else if (JOY_NEW(DPAD_LEFT)
|| (JOY_NEW(L_BUTTON) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_LR))
{
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0, 0x10, RGB_BLACK);
sPokedexView->screenSwitchState = 2;
gTasks[taskId].func = Task_SwitchScreensFromSizeScreen;
PlaySE(SE_DEX_PAGE);
}
}
static void Task_SwitchScreensFromSizeScreen(u8 taskId)
{
if (!gPaletteFade.active)
{
FreeAndDestroyMonPicSprite(gTasks[taskId].tMonSpriteId);
FreeAndDestroyTrainerPicSprite(gTasks[taskId].tTrainerSpriteId);
switch (sPokedexView->screenSwitchState)
{
default:
case 1:
gTasks[taskId].func = Task_LoadInfoScreen;
break;
case 2:
gTasks[taskId].func = Task_LoadCryScreen;
break;
}
}
}
#undef tScrolling
#undef tMonSpriteDone
#undef tBgLoaded
#undef tSkipCry
#undef tMonSpriteId
#undef tTrainerSpriteId
//************************************
//* *
//* Search Screen *
//* *
//************************************
static void Task_WaitForExitSearch(u8 taskId)
{
if (!gTasks[gTasks[taskId].tLoadScreenTaskId].isActive)
{
ClearMonSprites();
TryDestroyStatBars();
TryDestroyStatBarsBg();
// Search produced results
if (sPokedexView->screenSwitchState != 0)
{
sPokedexView->selectedPokemon = 0;
sPokedexView->pokeBallRotation = POKEBALL_ROTATION_TOP;
gTasks[taskId].func = Task_OpenSearchResults;
}
// Search didn't produce results
else
{
sPokedexView->pokeBallRotation = sPokedexView->pokeBallRotationBackup;
sPokedexView->selectedPokemon = sPokedexView->selectedPokemonBackup;
sPokedexView->dexMode = sPokedexView->dexModeBackup;
if (!IsNationalPokedexEnabled())
sPokedexView->dexMode = DEX_MODE_HOENN;
sPokedexView->dexOrder = sPokedexView->dexOrderBackup;
gTasks[taskId].func = Task_OpenPokedexMainPage;
}
}
}
static void Task_OpenSearchResults(u8 taskId)
{
sPokedexView->isSearchResults = TRUE;
sPokedexView->sEvoScreenData.fromEvoPage = FALSE;
sPokedexView->formSpecies = 0;
if (LoadPokedexListPage(PAGE_SEARCH_RESULTS))
gTasks[taskId].func = Task_HandleSearchResultsInput;
}
static void Task_HandleSearchResultsInput(u8 taskId)
{
SetGpuReg(REG_OFFSET_BG0VOFS, sPokedexView->menuY);
if (sPokedexView->menuY)
{
sPokedexView->menuY -= 8;
if (sPokedexView->menuIsOpen == FALSE && sPokedexView->menuY == 8)
{
CreateStatBars(&sPokedexView->pokedexList[sPokedexView->selectedPokemon]);
CreateStatBarsBg();
}
}
else
{
if (JOY_NEW(A_BUTTON) && sPokedexView->pokedexList[sPokedexView->selectedPokemon].seen)
{
u32 a;
TryDestroyStatBars();
UpdateSelectedMonSpriteId();
a = (1 << (gSprites[sPokedexView->selectedMonSpriteId].oam.paletteNum + 16));
gSprites[sPokedexView->selectedMonSpriteId].callback = SpriteCB_MoveMonForInfoScreen;
BeginNormalPaletteFade(~a, 0, 0, 0x10, RGB_BLACK);
gTasks[taskId].func = Task_OpenSearchResultsInfoScreenAfterMonMovement;
PlaySE(SE_PIN);
FreeWindowAndBgBuffers();
}
else if (JOY_NEW(START_BUTTON))
{
TryDestroyStatBars();
TryDestroyStatBarsBg();
sPokedexView->menuY = 0;
sPokedexView->menuIsOpen = TRUE;
sPokedexView->menuCursorPos = 0;
gTasks[taskId].func = Task_HandleSearchResultsStartMenuInput;
PlaySE(SE_SELECT);
}
else if (JOY_NEW(SELECT_BUTTON))
{
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
gTasks[taskId].tLoadScreenTaskId = LoadSearchMenu();
sPokedexView->screenSwitchState = 0;
gTasks[taskId].func = Task_WaitForExitSearch;
PlaySE(SE_PC_LOGIN);
FreeWindowAndBgBuffers();
}
else if (JOY_NEW(B_BUTTON))
{
TryDestroyStatBars();
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
gTasks[taskId].func = Task_ReturnToPokedexFromSearchResults;
PlaySE(SE_PC_OFF);
}
else
{
//Handle D-pad
sPokedexView->selectedPokemon = TryDoPokedexScroll(sPokedexView->selectedPokemon, 0xE);
if (sPokedexView->scrollTimer)
gTasks[taskId].func = Task_WaitForSearchResultsScroll;
else if (!sPokedexView->scrollTimer && !sPokedexView->scrollSpeed && sPokedexView->justScrolled)
CreateStatBars(&sPokedexView->pokedexList[sPokedexView->selectedPokemon]);
}
}
}
static void Task_WaitForSearchResultsScroll(u8 taskId)
{
TryDestroyStatBars();
if (UpdateDexListScroll(sPokedexView->scrollDirection, sPokedexView->scrollMonIncrement, sPokedexView->maxScrollTimer))
gTasks[taskId].func = Task_HandleSearchResultsInput;
}
static void Task_HandleSearchResultsStartMenuInput(u8 taskId)
{
SetGpuReg(REG_OFFSET_BG0VOFS, sPokedexView->menuY);
if (sPokedexView->menuY != 96)
{
sPokedexView->menuY += 8;
}
else
{
if (JOY_NEW(A_BUTTON))
{
switch (sPokedexView->menuCursorPos)
{
case 0: //BACK TO LIST
default:
gMain.newKeys |= START_BUTTON;
break;
case 1: //LIST TOP
sPokedexView->selectedPokemon = 0;
sPokedexView->pokeBallRotation = POKEBALL_ROTATION_TOP;
ClearMonSprites();
CreateMonSpritesAtPos(sPokedexView->selectedPokemon, 0xE);
gMain.newKeys |= START_BUTTON;
break;
case 2: //LIST BOTTOM
sPokedexView->selectedPokemon = sPokedexView->pokemonListCount - 1;
sPokedexView->pokeBallRotation = sPokedexView->pokemonListCount * 16 + POKEBALL_ROTATION_BOTTOM;
ClearMonSprites();
CreateMonSpritesAtPos(sPokedexView->selectedPokemon, 0xE);
gMain.newKeys |= START_BUTTON;
break;
case 3: //BACK TO POKEDEX
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
gTasks[taskId].func = Task_ReturnToPokedexFromSearchResults;
PlaySE(SE_TRUCK_DOOR);
break;
case 4: //CLOSE POKEDEX
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
gTasks[taskId].func = Task_ClosePokedexFromSearchResultsStartMenu;
PlaySE(SE_PC_OFF);
break;
}
}
//Exit menu when Start or B is pressed
if (JOY_NEW(START_BUTTON | B_BUTTON))
{
sPokedexView->menuIsOpen = FALSE;
gTasks[taskId].func = Task_HandleSearchResultsInput;
PlaySE(SE_SELECT);
}
else if (JOY_REPEAT(DPAD_UP) && sPokedexView->menuCursorPos)
{
sPokedexView->menuCursorPos--;
PlaySE(SE_SELECT);
}
else if (JOY_REPEAT(DPAD_DOWN) && sPokedexView->menuCursorPos < 4)
{
sPokedexView->menuCursorPos++;
PlaySE(SE_SELECT);
}
}
}
static void Task_OpenSearchResultsInfoScreenAfterMonMovement(u8 taskId)
{
if (gSprites[sPokedexView->selectedMonSpriteId].x == MON_PAGE_X && gSprites[sPokedexView->selectedMonSpriteId].y == MON_PAGE_Y)
{
sPokedexView->currentPageBackup = sPokedexView->currentPage;
gTasks[taskId].tLoadScreenTaskId = LoadInfoScreen(&sPokedexView->pokedexList[sPokedexView->selectedPokemon], sPokedexView->selectedMonSpriteId);
sPokedexView->selectedMonSpriteId = -1;
gTasks[taskId].func = Task_WaitForExitSearchResultsInfoScreen;
}
}
static void Task_WaitForExitSearchResultsInfoScreen(u8 taskId)
{
if (gTasks[gTasks[taskId].tLoadScreenTaskId].isActive)
{
// While active, handle scroll input
if (sPokedexView->currentPage == PAGE_INFO && !IsInfoScreenScrolling(gTasks[taskId].tLoadScreenTaskId) && TryDoInfoScreenScroll())
StartInfoScreenScroll(&sPokedexView->pokedexList[sPokedexView->selectedPokemon], gTasks[taskId].tLoadScreenTaskId);
}
else
{
// Exiting, back to search results
gTasks[taskId].func = Task_OpenSearchResults;
}
}
static void Task_ReturnToPokedexFromSearchResults(u8 taskId)
{
if (!gPaletteFade.active)
{
sPokedexView->pokeBallRotation = sPokedexView->pokeBallRotationBackup;
sPokedexView->selectedPokemon = sPokedexView->selectedPokemonBackup;
sPokedexView->dexMode = sPokedexView->dexModeBackup;
if (!IsNationalPokedexEnabled())
sPokedexView->dexMode = DEX_MODE_HOENN;
sPokedexView->dexOrder = sPokedexView->dexOrderBackup;
gTasks[taskId].func = Task_OpenPokedexMainPage;
ClearMonSprites();
FreeWindowAndBgBuffers();
}
}
static void Task_ClosePokedexFromSearchResultsStartMenu(u8 taskId)
{
if (!gPaletteFade.active)
{
sPokedexView->pokeBallRotation = sPokedexView->pokeBallRotationBackup;
sPokedexView->selectedPokemon = sPokedexView->selectedPokemonBackup;
sPokedexView->dexMode = sPokedexView->dexModeBackup;
if (!IsNationalPokedexEnabled())
sPokedexView->dexMode = DEX_MODE_HOENN;
sPokedexView->dexOrder = sPokedexView->dexOrderBackup;
gTasks[taskId].func = Task_ClosePokedex;
}
}
#undef tLoadScreenTaskId
//************************************
//* *
//* Search code *
//* *
//************************************
static int DoPokedexSearch(u8 dexMode, u8 order, u8 abcGroup, u8 bodyColor, u8 type1, u8 type2)
{
u16 species;
u16 i;
u16 resultsCount;
u8 types[2];
CreatePokedexList(dexMode, order);
for (i = 0, resultsCount = 0; i < NATIONAL_DEX_COUNT; i++)
{
if (sPokedexView->pokedexList[i].seen)
{
sPokedexView->pokedexList[resultsCount] = sPokedexView->pokedexList[i];
resultsCount++;
}
}
sPokedexView->pokemonListCount = resultsCount;
// Search by name
if (abcGroup != 0xFF)
{
for (i = 0, resultsCount = 0; i < sPokedexView->pokemonListCount; i++)
{
u8 firstLetter;
species = NationalPokedexNumToSpecies(sPokedexView->pokedexList[i].dexNum);
firstLetter = GetSpeciesName(species)[0];
if (LETTER_IN_RANGE_UPPER(firstLetter, abcGroup) || LETTER_IN_RANGE_LOWER(firstLetter, abcGroup))
{
sPokedexView->pokedexList[resultsCount] = sPokedexView->pokedexList[i];
resultsCount++;
}
}
sPokedexView->pokemonListCount = resultsCount;
}
// Search by body color
if (bodyColor != 0xFF)
{
for (i = 0, resultsCount = 0; i < sPokedexView->pokemonListCount; i++)
{
species = NationalPokedexNumToSpecies(sPokedexView->pokedexList[i].dexNum);
if (bodyColor == gSpeciesInfo[species].bodyColor)
{
sPokedexView->pokedexList[resultsCount] = sPokedexView->pokedexList[i];
resultsCount++;
}
}
sPokedexView->pokemonListCount = resultsCount;
}
// Search by type
if (type1 != TYPE_NONE || type2 != TYPE_NONE)
{
if (type1 == TYPE_NONE)
{
type1 = type2;
type2 = TYPE_NONE;
}
if (type2 == TYPE_NONE)
{
for (i = 0, resultsCount = 0; i < sPokedexView->pokemonListCount; i++)
{
if (sPokedexView->pokedexList[i].owned)
{
species = NationalPokedexNumToSpecies(sPokedexView->pokedexList[i].dexNum);
types[0] = gSpeciesInfo[species].types[0];
types[1] = gSpeciesInfo[species].types[1];
if (types[0] == type1 || types[1] == type1)
{
sPokedexView->pokedexList[resultsCount] = sPokedexView->pokedexList[i];
resultsCount++;
}
}
}
}
else
{
for (i = 0, resultsCount = 0; i < sPokedexView->pokemonListCount; i++)
{
if (sPokedexView->pokedexList[i].owned)
{
species = NationalPokedexNumToSpecies(sPokedexView->pokedexList[i].dexNum);
types[0] = gSpeciesInfo[species].types[0];
types[1] = gSpeciesInfo[species].types[1];
if ((types[0] == type1 && types[1] == type2) || (types[0] == type2 && types[1] == type1))
{
sPokedexView->pokedexList[resultsCount] = sPokedexView->pokedexList[i];
resultsCount++;
}
}
}
}
sPokedexView->pokemonListCount = resultsCount;
}
if (sPokedexView->pokemonListCount != 0)
{
for (i = sPokedexView->pokemonListCount; i < NATIONAL_DEX_COUNT; i++)
{
sPokedexView->pokedexList[i].dexNum = 0xFFFF;
sPokedexView->pokedexList[i].seen = FALSE;
sPokedexView->pokedexList[i].owned = FALSE;
}
}
return resultsCount;
}
static u8 LoadSearchMenu(void)
{
return CreateTask(Task_LoadSearchMenu, 0);
}
static void PrintSearchText(const u8 *str, u32 x, u32 y)
{
u8 color[3];
color[0] = TEXT_COLOR_TRANSPARENT;
color[1] = TEXT_DYNAMIC_COLOR_6;
color[2] = TEXT_COLOR_DARK_GRAY;
AddTextPrinterParameterized4(0, FONT_NORMAL, x, y, 0, 0, color, TEXT_SKIP_DRAW, str);
}
static void ClearSearchMenuRect(u32 x, u32 y, u32 width, u32 height)
{
FillWindowPixelRect(0, PIXEL_FILL(0), x, y, width, height);
}
// Search task data
#define tTopBarItem data[0]
#define tMenuItem data[1]
#define tCursorPos_Mode data[2]
#define tScrollOffset_Mode data[3]
#define tCursorPos_Order data[4]
#define tScrollOffset_Order data[5]
#define tCursorPos_Name data[6]
#define tScrollOffset_Name data[7]
#define tCursorPos_Color data[8]
#define tScrollOffset_Color data[9]
#define tCursorPos_TypeLeft data[10]
#define tScrollOffset_TypeLeft data[11]
#define tCursorPos_TypeRight data[12]
#define tScrollOffset_TypeRight data[13]
#define tCursorPos data[14]
#define tScrollOffset data[15]
static void Task_LoadSearchMenu(u8 taskId)
{
u16 i;
switch (gMain.state)
{
default:
case 0:
if (!gPaletteFade.active)
{
sPokedexView->currentPage = PAGE_SEARCH;
ResetOtherVideoRegisters(0);
ResetBgsAndClearDma3BusyFlags(0);
InitBgsFromTemplates(0, sSearchMenu_BgTemplate, ARRAY_COUNT(sSearchMenu_BgTemplate));
SetBgTilemapBuffer(3, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(2, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(1, AllocZeroed(BG_SCREEN_SIZE));
SetBgTilemapBuffer(0, AllocZeroed(BG_SCREEN_SIZE));
InitWindows(sSearchMenu_WindowTemplate);
DeactivateAllTextPrinters();
PutWindowTilemap(0);
if (!HGSS_DECAPPED)
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_MenuSearch_Gfx, 0x2000, 0, 0);
else
DecompressAndLoadBgGfxUsingHeap(3, sPokedexPlusHGSS_MenuSearch_DECA_Gfx, 0x2000, 0, 0);
if (!IsNationalPokedexEnabled())
CopyToBgTilemapBuffer(3, sPokedexPlusHGSS_ScreenSearchHoenn_Tilemap, 0, 0);
else
CopyToBgTilemapBuffer(3, sPokedexPlusHGSS_ScreenSearchNational_Tilemap, 0, 0);
if (!HGSS_DARK_MODE)
LoadPalette(sPokedexPlusHGSS_MenuSearch_Pal + 1, BG_PLTT_ID(0) + 1, PLTT_SIZEOF(4 * 16 - 1));
else
LoadPalette(sPokedexPlusHGSS_MenuSearch_dark_Pal + 1, BG_PLTT_ID(0) + 1, PLTT_SIZEOF(4 * 16 - 1));
gMain.state = 1;
}
break;
case 1:
LoadCompressedSpriteSheet(&sInterfaceSpriteSheet[HGSS_DECAPPED]);
LoadSpritePalettes(sInterfaceSpritePalette);
LoadSpritePalettes(sStatBarSpritePal);
CreateSearchParameterScrollArrows(taskId);
for (i = 0; i < NUM_TASK_DATA; i++)
gTasks[taskId].data[i] = 0;
SetDefaultSearchModeAndOrder(taskId);
HighlightSelectedSearchTopBarItem(SEARCH_TOPBAR_SEARCH);
PrintSelectedSearchParameters(taskId);
CopyWindowToVram(0, COPYWIN_FULL);
CopyBgTilemapBufferToVram(1);
CopyBgTilemapBufferToVram(2);
CopyBgTilemapBufferToVram(3);
gMain.state++;
break;
case 2:
BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK);
sPokedexView->statBarsSpriteId = 0xFF;
CreateStatBars(&sPokedexView->pokedexList[sPokedexView->selectedPokemon]);
gMain.state++;
break;
case 3:
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
HideBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
gMain.state++;
break;
case 4:
if (!gPaletteFade.active)
{
gTasks[taskId].func = Task_SwitchToSearchMenuTopBar;
gMain.state = 0;
}
break;
}
}
static void FreeSearchWindowAndBgBuffers(void)
{
void *tilemapBuffer;
FreeAllWindowBuffers();
tilemapBuffer = GetBgTilemapBuffer(0);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(1);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(2);
if (tilemapBuffer)
Free(tilemapBuffer);
tilemapBuffer = GetBgTilemapBuffer(3);
if (tilemapBuffer)
Free(tilemapBuffer);
}
static void Task_SwitchToSearchMenuTopBar(u8 taskId)
{
HighlightSelectedSearchTopBarItem(gTasks[taskId].tTopBarItem);
PrintSelectedSearchParameters(taskId);
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
gTasks[taskId].func = Task_HandleSearchTopBarInput;
}
static void Task_HandleSearchTopBarInput(u8 taskId)
{
if (JOY_NEW(B_BUTTON))
{
PlaySE(SE_PC_OFF);
gTasks[taskId].func = Task_ExitSearch;
return;
}
if (JOY_NEW(A_BUTTON))
{
switch (gTasks[taskId].tTopBarItem)
{
case SEARCH_TOPBAR_SEARCH:
PlaySE(SE_PIN);
gTasks[taskId].tMenuItem = SEARCH_NAME;
gTasks[taskId].func = Task_SwitchToSearchMenu;
break;
case SEARCH_TOPBAR_SHIFT:
PlaySE(SE_PIN);
gTasks[taskId].tMenuItem = SEARCH_ORDER;
gTasks[taskId].func = Task_SwitchToSearchMenu;
break;
case SEARCH_TOPBAR_CANCEL:
PlaySE(SE_PC_OFF);
gTasks[taskId].func = Task_ExitSearch;
break;
}
return;
}
if (JOY_NEW(DPAD_LEFT) && gTasks[taskId].tTopBarItem > SEARCH_TOPBAR_SEARCH)
{
PlaySE(SE_DEX_PAGE);
gTasks[taskId].tTopBarItem--;
HighlightSelectedSearchTopBarItem(gTasks[taskId].tTopBarItem);
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
}
if (JOY_NEW(DPAD_RIGHT) && gTasks[taskId].tTopBarItem < SEARCH_TOPBAR_CANCEL)
{
PlaySE(SE_DEX_PAGE);
gTasks[taskId].tTopBarItem++;
HighlightSelectedSearchTopBarItem(gTasks[taskId].tTopBarItem);
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
}
}
static void Task_SwitchToSearchMenu(u8 taskId)
{
HighlightSelectedSearchMenuItem(gTasks[taskId].tTopBarItem, gTasks[taskId].tMenuItem);
PrintSelectedSearchParameters(taskId);
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
gTasks[taskId].func = Task_HandleSearchMenuInput;
}
// Input for main search menu
static void Task_HandleSearchMenuInput(u8 taskId)
{
const u8 (*movementMap)[4];
if (gTasks[taskId].tTopBarItem != SEARCH_TOPBAR_SEARCH)
{
if (!IsNationalPokedexEnabled())
movementMap = sSearchMovementMap_ShiftHoennDex;
else
movementMap = sSearchMovementMap_ShiftNatDex;
}
else
{
if (!IsNationalPokedexEnabled())
movementMap = sSearchMovementMap_SearchHoennDex;
else
movementMap = sSearchMovementMap_SearchNatDex;
}
if (JOY_NEW(B_BUTTON))
{
PlaySE(SE_BALL);
SetDefaultSearchModeAndOrder(taskId);
gTasks[taskId].func = Task_SwitchToSearchMenuTopBar;
return;
}
if (JOY_NEW(A_BUTTON))
{
if (gTasks[taskId].tMenuItem == SEARCH_OK)
{
if (gTasks[taskId].tTopBarItem != SEARCH_TOPBAR_SEARCH)
{
sPokeBallRotation = POKEBALL_ROTATION_TOP;
sPokedexView->pokeBallRotationBackup = POKEBALL_ROTATION_TOP;
sLastSelectedPokemon = 0;
sPokedexView->selectedPokemonBackup = 0;
gSaveBlock2Ptr->pokedex.mode = GetSearchModeSelection(taskId, SEARCH_MODE);
if (!IsNationalPokedexEnabled())
gSaveBlock2Ptr->pokedex.mode = DEX_MODE_HOENN;
sPokedexView->dexModeBackup = gSaveBlock2Ptr->pokedex.mode;
gSaveBlock2Ptr->pokedex.order = GetSearchModeSelection(taskId, SEARCH_ORDER);
sPokedexView->dexOrderBackup = gSaveBlock2Ptr->pokedex.order;
PlaySE(SE_PC_OFF);
gTasks[taskId].func = Task_ExitSearch;
}
else
{
EraseAndPrintSearchTextBox(gText_SearchingPleaseWait);
gTasks[taskId].func = Task_StartPokedexSearch;
PlaySE(SE_DEX_SEARCH);
CopyWindowToVram(0, COPYWIN_GFX);
}
}
else
{
PlaySE(SE_PIN);
gTasks[taskId].func = Task_SelectSearchMenuItem;
}
return;
}
if (JOY_NEW(DPAD_LEFT) && movementMap[gTasks[taskId].tMenuItem][0] != 0xFF)
{
PlaySE(SE_SELECT);
gTasks[taskId].tMenuItem = movementMap[gTasks[taskId].tMenuItem][0];
HighlightSelectedSearchMenuItem(gTasks[taskId].tTopBarItem, gTasks[taskId].tMenuItem);
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
}
if (JOY_NEW(DPAD_RIGHT) && movementMap[gTasks[taskId].tMenuItem][1] != 0xFF)
{
PlaySE(SE_SELECT);
gTasks[taskId].tMenuItem = movementMap[gTasks[taskId].tMenuItem][1];
HighlightSelectedSearchMenuItem(gTasks[taskId].tTopBarItem, gTasks[taskId].tMenuItem);
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
}
if (JOY_NEW(DPAD_UP) && movementMap[gTasks[taskId].tMenuItem][2] != 0xFF)
{
PlaySE(SE_SELECT);
gTasks[taskId].tMenuItem = movementMap[gTasks[taskId].tMenuItem][2];
HighlightSelectedSearchMenuItem(gTasks[taskId].tTopBarItem, gTasks[taskId].tMenuItem);
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
}
if (JOY_NEW(DPAD_DOWN) && movementMap[gTasks[taskId].tMenuItem][3] != 0xFF)
{
PlaySE(SE_SELECT);
gTasks[taskId].tMenuItem = movementMap[gTasks[taskId].tMenuItem][3];
HighlightSelectedSearchMenuItem(gTasks[taskId].tTopBarItem, gTasks[taskId].tMenuItem);
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
}
}
static void Task_StartPokedexSearch(u8 taskId)
{
u8 dexMode = GetSearchModeSelection(taskId, SEARCH_MODE);
u8 order = GetSearchModeSelection(taskId, SEARCH_ORDER);
u8 abcGroup = GetSearchModeSelection(taskId, SEARCH_NAME);
u8 bodyColor = GetSearchModeSelection(taskId, SEARCH_COLOR);
u8 type1 = GetSearchModeSelection(taskId, SEARCH_TYPE_LEFT);
u8 type2 = GetSearchModeSelection(taskId, SEARCH_TYPE_RIGHT);
DoPokedexSearch(dexMode, order, abcGroup, bodyColor, type1, type2);
gTasks[taskId].func = Task_WaitAndCompleteSearch;
}
static void Task_WaitAndCompleteSearch(u8 taskId)
{
if (!IsSEPlaying())
{
if (sPokedexView->pokemonListCount != 0)
{
PlaySE(SE_SUCCESS);
EraseAndPrintSearchTextBox(gText_SearchCompleted);
}
else
{
PlaySE(SE_FAILURE);
EraseAndPrintSearchTextBox(gText_NoMatchingPkmnWereFound);
}
gTasks[taskId].func = Task_SearchCompleteWaitForInput;
CopyWindowToVram(0, COPYWIN_GFX);
}
}
static void Task_SearchCompleteWaitForInput(u8 taskId)
{
if (JOY_NEW(A_BUTTON))
{
if (sPokedexView->pokemonListCount != 0)
{
// Return to dex list and show search results
sPokedexView->screenSwitchState = 1;
sPokedexView->dexMode = GetSearchModeSelection(taskId, SEARCH_MODE);
sPokedexView->dexOrder = GetSearchModeSelection(taskId, SEARCH_ORDER);
gTasks[taskId].func = Task_ExitSearch;
PlaySE(SE_PC_OFF);
}
else
{
gTasks[taskId].func = Task_SwitchToSearchMenu;
PlaySE(SE_BALL);
}
}
}
static void Task_SelectSearchMenuItem(u8 taskId)
{
u8 menuItem;
s16 *cursorPos;
s16 *scrollOffset;
DrawOrEraseSearchParameterBox(FALSE);
menuItem = gTasks[taskId].tMenuItem;
cursorPos = &gTasks[taskId].data[sSearchOptions[menuItem].taskDataCursorPos];
scrollOffset = &gTasks[taskId].data[sSearchOptions[menuItem].taskDataScrollOffset];
gTasks[taskId].tCursorPos = *cursorPos;
gTasks[taskId].tScrollOffset = *scrollOffset;
PrintSearchParameterText(taskId);
PrintSelectorArrow(*cursorPos);
gTasks[taskId].func = Task_HandleSearchParameterInput;
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
}
// Input for scrolling parameter box in right column
static void Task_HandleSearchParameterInput(u8 taskId)
{
u8 menuItem;
const struct SearchOptionText *texts;
s16 *cursorPos;
s16 *scrollOffset;
u16 maxOption;
bool8 moved;
menuItem = gTasks[taskId].tMenuItem;
texts = sSearchOptions[menuItem].texts;
cursorPos = &gTasks[taskId].data[sSearchOptions[menuItem].taskDataCursorPos];
scrollOffset = &gTasks[taskId].data[sSearchOptions[menuItem].taskDataScrollOffset];
maxOption = sSearchOptions[menuItem].numOptions - 1;
if (JOY_NEW(A_BUTTON))
{
PlaySE(SE_PIN);
ClearSearchParameterBoxText();
DrawOrEraseSearchParameterBox(TRUE);
gTasks[taskId].func = Task_SwitchToSearchMenu;
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
return;
}
if (JOY_NEW(B_BUTTON))
{
PlaySE(SE_BALL);
ClearSearchParameterBoxText();
DrawOrEraseSearchParameterBox(TRUE);
*cursorPos = gTasks[taskId].tCursorPos;
*scrollOffset = gTasks[taskId].tScrollOffset;
gTasks[taskId].func = Task_SwitchToSearchMenu;
CopyWindowToVram(0, COPYWIN_GFX);
CopyBgTilemapBufferToVram(3);
return;
}
moved = FALSE;
if (JOY_REPEAT(DPAD_UP))
{
if (*cursorPos != 0)
{
// Move cursor up
EraseSelectorArrow(*cursorPos);
(*cursorPos)--;
PrintSelectorArrow(*cursorPos);
moved = TRUE;
}
else if (*scrollOffset != 0)
{
// Scroll up
(*scrollOffset)--;
PrintSearchParameterText(taskId);
PrintSelectorArrow(*cursorPos);
moved = TRUE;
}
if (moved)
{
PlaySE(SE_SELECT);
EraseAndPrintSearchTextBox(texts[*cursorPos + *scrollOffset].description);
CopyWindowToVram(0, COPYWIN_GFX);
}
return;
}
if (JOY_REPEAT(DPAD_DOWN))
{
if (*cursorPos < MAX_SEARCH_PARAM_CURSOR_POS && *cursorPos < maxOption)
{
// Move cursor down
EraseSelectorArrow(*cursorPos);
(*cursorPos)++;
PrintSelectorArrow(*cursorPos);
moved = TRUE;
}
else if (maxOption > MAX_SEARCH_PARAM_CURSOR_POS && *scrollOffset < maxOption - MAX_SEARCH_PARAM_CURSOR_POS)
{
// Scroll down
(*scrollOffset)++;
PrintSearchParameterText(taskId);
PrintSelectorArrow(5);
moved = TRUE;
}
if (moved)
{
PlaySE(SE_SELECT);
EraseAndPrintSearchTextBox(texts[*cursorPos + *scrollOffset].description);
CopyWindowToVram(0, COPYWIN_GFX);
}
return;
}
}
static void Task_ExitSearch(u8 taskId)
{
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
gTasks[taskId].func = Task_ExitSearchWaitForFade;
}
static void Task_ExitSearchWaitForFade(u8 taskId)
{
if (!gPaletteFade.active)
{
FreeSearchWindowAndBgBuffers();
DestroyTask(taskId);
}
}
static void SetSearchRectHighlight(u8 flags, u8 x, u8 y, u8 width)
{
u16 i;
u16 temp; //should be a pointer, but does not match as one
u32 ptr = (u32)GetBgTilemapBuffer(3); //same as above
for (i = 0; i < width; i++)
{
temp = *(u16 *)(ptr + (y + 0) * 64 + (x + i) * 2);
temp &= 0x0fff;
temp |= (flags << 12);
*(u16 *)(ptr + (y + 0) * 64 + (x + i) * 2) = temp;
temp = *(u16 *)(ptr + (y + 1) * 64 + (x + i) * 2);
temp &= 0x0fff;
temp |= (flags << 12);
*(u16 *)(ptr + (y + 1) * 64 + (x + i) * 2) = temp;
}
}
#define SEARCH_BG_SEARCH SEARCH_TOPBAR_SEARCH
#define SEARCH_BG_SHIFT SEARCH_TOPBAR_SHIFT
#define SEARCH_BG_CANCEL SEARCH_TOPBAR_CANCEL
#define SEARCH_BG_NAME (SEARCH_NAME + SEARCH_TOPBAR_COUNT)
#define SEARCH_BG_COLOR (SEARCH_COLOR + SEARCH_TOPBAR_COUNT)
#define SEARCH_BG_TYPE_SELECTION_LEFT (SEARCH_TYPE_LEFT + SEARCH_TOPBAR_COUNT)
#define SEARCH_BG_TYPE_SELECTION_RIGHT (SEARCH_TYPE_RIGHT + SEARCH_TOPBAR_COUNT)
#define SEARCH_BG_ORDER (SEARCH_ORDER + SEARCH_TOPBAR_COUNT)
#define SEARCH_BG_MODE (SEARCH_MODE + SEARCH_TOPBAR_COUNT)
#define SEARCH_BG_OK (SEARCH_OK + SEARCH_TOPBAR_COUNT)
#define SEARCH_BG_TYPE_TITLE (SEARCH_COUNT + SEARCH_TOPBAR_COUNT)
static void DrawSearchMenuItemBgHighlight(u8 searchBg, bool8 unselected, bool8 disabled)
{
u8 highlightFlags = (unselected & 1) | ((disabled & 1) << 1);
switch (searchBg)
{
case SEARCH_BG_SEARCH:
case SEARCH_BG_SHIFT:
case SEARCH_BG_CANCEL:
SetSearchRectHighlight(highlightFlags, sSearchMenuTopBarItems[searchBg].highlightX, sSearchMenuTopBarItems[searchBg].highlightY, sSearchMenuTopBarItems[searchBg].highlightWidth);
break;
case SEARCH_BG_NAME:
case SEARCH_BG_COLOR:
case SEARCH_BG_ORDER:
case SEARCH_BG_MODE:
SetSearchRectHighlight(highlightFlags, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].titleBgX, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].titleBgY, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].titleBgWidth);
// fall through, draw selectionBg for above
case SEARCH_BG_TYPE_SELECTION_LEFT:
case SEARCH_BG_TYPE_SELECTION_RIGHT:
SetSearchRectHighlight(highlightFlags, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].selectionBgX, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].selectionBgY, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].selectionBgWidth);
break;
case SEARCH_BG_TYPE_TITLE:
SetSearchRectHighlight(highlightFlags, sSearchMenuItems[SEARCH_TYPE_LEFT].titleBgX, sSearchMenuItems[SEARCH_TYPE_LEFT].titleBgY, sSearchMenuItems[SEARCH_TYPE_LEFT].titleBgWidth);
break;
case SEARCH_BG_OK:
if (!IsNationalPokedexEnabled())
SetSearchRectHighlight(highlightFlags, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].titleBgX, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].titleBgY - 2, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].titleBgWidth);
else
SetSearchRectHighlight(highlightFlags, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].titleBgX, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].titleBgY, sSearchMenuItems[searchBg - SEARCH_TOPBAR_COUNT].titleBgWidth);
break;
}
}
static void SetInitialSearchMenuBgHighlights(u8 topBarItem)
{
switch (topBarItem)
{
case SEARCH_TOPBAR_SEARCH:
DrawSearchMenuItemBgHighlight(SEARCH_BG_SEARCH, FALSE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_SHIFT, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_CANCEL, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_NAME, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_COLOR, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_TITLE, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_SELECTION_LEFT, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_SELECTION_RIGHT, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_ORDER, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_MODE, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_OK, TRUE, FALSE);
break;
case SEARCH_TOPBAR_SHIFT:
DrawSearchMenuItemBgHighlight(SEARCH_BG_SEARCH, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_SHIFT, FALSE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_CANCEL, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_NAME, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_COLOR, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_TITLE, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_SELECTION_LEFT, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_SELECTION_RIGHT, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_ORDER, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_MODE, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_OK, TRUE, FALSE);
break;
case SEARCH_TOPBAR_CANCEL:
DrawSearchMenuItemBgHighlight(SEARCH_BG_SEARCH, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_SHIFT, TRUE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_CANCEL, FALSE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_NAME, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_COLOR, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_TITLE, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_SELECTION_LEFT, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_SELECTION_RIGHT, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_ORDER, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_MODE, TRUE, TRUE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_OK, TRUE, TRUE);
break;
}
}
static void HighlightSelectedSearchTopBarItem(u8 topBarItem)
{
SetInitialSearchMenuBgHighlights(topBarItem);
EraseAndPrintSearchTextBox(sSearchMenuTopBarItems[topBarItem].description);
}
static void HighlightSelectedSearchMenuItem(u8 topBarItem, u8 menuItem)
{
SetInitialSearchMenuBgHighlights(topBarItem);
switch (menuItem)
{
case SEARCH_NAME:
DrawSearchMenuItemBgHighlight(SEARCH_BG_NAME, FALSE, FALSE);
break;
case SEARCH_COLOR:
DrawSearchMenuItemBgHighlight(SEARCH_BG_COLOR, FALSE, FALSE);
break;
case SEARCH_TYPE_LEFT:
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_TITLE, FALSE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_SELECTION_LEFT, FALSE, FALSE);
break;
case SEARCH_TYPE_RIGHT:
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_TITLE, FALSE, FALSE);
DrawSearchMenuItemBgHighlight(SEARCH_BG_TYPE_SELECTION_RIGHT, FALSE, FALSE);
break;
case SEARCH_ORDER:
DrawSearchMenuItemBgHighlight(SEARCH_BG_ORDER, FALSE, FALSE);
break;
case SEARCH_MODE:
DrawSearchMenuItemBgHighlight(SEARCH_BG_MODE, FALSE, FALSE);
break;
case SEARCH_OK:
DrawSearchMenuItemBgHighlight(SEARCH_BG_OK, FALSE, FALSE);
break;
}
EraseAndPrintSearchTextBox(sSearchMenuItems[menuItem].description);
}
// Prints the currently selected search parameters in the search menu selection boxes
static void PrintSelectedSearchParameters(u8 taskId)
{
u16 searchParamId;
ClearSearchMenuRect(40, 16, 96, 80);
searchParamId = gTasks[taskId].tCursorPos_Name + gTasks[taskId].tScrollOffset_Name;
PrintSearchText(sDexSearchNameOptions[searchParamId].title, 0x2D, 0x11);
searchParamId = gTasks[taskId].tCursorPos_Color + gTasks[taskId].tScrollOffset_Color;
PrintSearchText(sDexSearchColorOptions[searchParamId].title, 0x2D, 0x21);
searchParamId = gTasks[taskId].tCursorPos_TypeLeft + gTasks[taskId].tScrollOffset_TypeLeft;
PrintSearchText(sDexSearchTypeOptions[searchParamId].title, 0x2D, 0x31);
searchParamId = gTasks[taskId].tCursorPos_TypeRight + gTasks[taskId].tScrollOffset_TypeRight;
PrintSearchText(sDexSearchTypeOptions[searchParamId].title, 0x5D, 0x31);
searchParamId = gTasks[taskId].tCursorPos_Order + gTasks[taskId].tScrollOffset_Order;
PrintSearchText(sDexOrderOptions[searchParamId].title, 0x2D, 0x41);
if (IsNationalPokedexEnabled())
{
searchParamId = gTasks[taskId].tCursorPos_Mode + gTasks[taskId].tScrollOffset_Mode;
PrintSearchText(sDexModeOptions[searchParamId].title, 0x2D, 0x51);
}
}
static void DrawOrEraseSearchParameterBox(bool8 erase)
{
u16 i;
u16 j;
u16 *ptr = GetBgTilemapBuffer(3);
if (!erase)
{
*(ptr + 0x11) = 0xC0B;
for (i = 0x12; i < 0x1F; i++)
*(ptr + i) = 0x80D;
for (j = 1; j < 13; j++)
{
*(ptr + 0x11 + j * 32) = 0x40A;
for (i = 0x12; i < 0x1F; i++)
*(ptr + j * 32 + i) = 2;
}
*(ptr + 0x1B1) = 0x40B;
for (i = 0x12; i < 0x1F; i++)
*(ptr + 0x1A0 + i) = 0xD;
}
else
{
for (j = 0; j < 14; j++)
{
for (i = 0x11; i < 0x1E; i++)
{
*(ptr + j * 32 + i) = 0x4F;
}
}
}
}
// Prints the currently viewable search parameter titles in the right-hand text box
// and the currently selected search parameter description in the bottom text box
static void PrintSearchParameterText(u8 taskId)
{
const struct SearchOptionText *texts = sSearchOptions[gTasks[taskId].tMenuItem].texts;
const s16 *cursorPos = &gTasks[taskId].data[sSearchOptions[gTasks[taskId].tMenuItem].taskDataCursorPos];
const s16 *scrollOffset = &gTasks[taskId].data[sSearchOptions[gTasks[taskId].tMenuItem].taskDataScrollOffset];
u16 i;
u16 j;
ClearSearchParameterBoxText();
for (i = 0, j = *scrollOffset; i < MAX_SEARCH_PARAM_ON_SCREEN && texts[j].title != NULL; i++, j++)
PrintSearchParameterTitle(i, texts[j].title);
EraseAndPrintSearchTextBox(texts[*cursorPos + *scrollOffset].description);
}
static u8 GetSearchModeSelection(u8 taskId, u8 option)
{
const s16 *cursorPos = &gTasks[taskId].data[sSearchOptions[option].taskDataCursorPos];
const s16 *scrollOffset = &gTasks[taskId].data[sSearchOptions[option].taskDataScrollOffset];
u16 id = *cursorPos + *scrollOffset;
switch (option)
{
default:
return 0;
case SEARCH_MODE:
return sPokedexModes[id];
case SEARCH_ORDER:
return sOrderOptions[id];
case SEARCH_NAME:
if (id == 0)
return 0xFF;
else
return id;
case SEARCH_COLOR:
if (id == 0)
return 0xFF;
else
return id - 1;
case SEARCH_TYPE_LEFT:
case SEARCH_TYPE_RIGHT:
return sDexSearchTypeIds[id];
}
}
static void SetDefaultSearchModeAndOrder(u8 taskId)
{
u16 selected;
switch (sPokedexView->dexModeBackup)
{
default:
case DEX_MODE_HOENN:
selected = DEX_MODE_HOENN;
break;
case DEX_MODE_NATIONAL:
selected = DEX_MODE_NATIONAL;
break;
}
gTasks[taskId].tCursorPos_Mode = selected;
switch (sPokedexView->dexOrderBackup)
{
default:
case ORDER_NUMERICAL:
selected = ORDER_NUMERICAL;
break;
case ORDER_ALPHABETICAL:
selected = ORDER_ALPHABETICAL;
break;
case ORDER_HEAVIEST:
selected = ORDER_HEAVIEST;
break;
case ORDER_LIGHTEST:
selected = ORDER_LIGHTEST;
break;
case ORDER_TALLEST:
selected = ORDER_TALLEST;
break;
case ORDER_SMALLEST:
selected = ORDER_SMALLEST;
break;
}
gTasks[taskId].tCursorPos_Order = selected;
}
static bool8 SearchParamCantScrollUp(u8 taskId)
{
u8 menuItem = gTasks[taskId].tMenuItem;
const s16 *scrollOffset = &gTasks[taskId].data[sSearchOptions[menuItem].taskDataScrollOffset];
u16 lastOption = sSearchOptions[menuItem].numOptions - 1;
if (lastOption > MAX_SEARCH_PARAM_CURSOR_POS && *scrollOffset != 0)
return FALSE;
else
return TRUE;
}
static bool8 SearchParamCantScrollDown(u8 taskId)
{
u8 menuItem = gTasks[taskId].tMenuItem;
const s16 *scrollOffset = &gTasks[taskId].data[sSearchOptions[menuItem].taskDataScrollOffset];
u16 lastOption = sSearchOptions[menuItem].numOptions - 1;
if (lastOption > MAX_SEARCH_PARAM_CURSOR_POS && *scrollOffset < lastOption - MAX_SEARCH_PARAM_CURSOR_POS)
return FALSE;
else
return TRUE;
}
#define sTaskId data[0]
static void SpriteCB_SearchParameterScrollArrow(struct Sprite *sprite)
{
if (gTasks[sprite->sTaskId].func == Task_HandleSearchParameterInput)
{
u8 val;
if (sprite->sIsDownArrow)
{
if (SearchParamCantScrollDown(sprite->sTaskId))
sprite->invisible = TRUE;
else
sprite->invisible = FALSE;
}
else
{
if (SearchParamCantScrollUp(sprite->sTaskId))
sprite->invisible = TRUE;
else
sprite->invisible = FALSE;
}
val = sprite->data[2] + sprite->sIsDownArrow * 128;
sprite->y2 = gSineTable[val] / 128;
sprite->data[2] += 8;
}
else
{
sprite->invisible = TRUE;
}
}
static void CreateSearchParameterScrollArrows(u8 taskId)
{
u8 spriteId;
spriteId = CreateSprite(&sScrollArrowSpriteTemplate, 184, 4, 0);
gSprites[spriteId].sTaskId = taskId;
gSprites[spriteId].sIsDownArrow = FALSE;
gSprites[spriteId].callback = SpriteCB_SearchParameterScrollArrow;
spriteId = CreateSprite(&sScrollArrowSpriteTemplate, 184, 108, 0);
gSprites[spriteId].sTaskId = taskId;
gSprites[spriteId].sIsDownArrow = TRUE;
gSprites[spriteId].vFlip = TRUE;
gSprites[spriteId].callback = SpriteCB_SearchParameterScrollArrow;
}
#undef sTaskId
#undef sIsDownArrow
static void EraseAndPrintSearchTextBox(const u8 *str)
{
ClearSearchMenuRect(8, 120, 224, 32);
PrintSearchText(str, 8, 121);
}
static void EraseSelectorArrow(u32 y)
{
ClearSearchMenuRect(144, y * 16 + 8, 8, 16);
}
static void PrintSelectorArrow(u32 y)
{
PrintSearchText(gText_SelectorArrow, 144, y * 16 + 9);
}
static void PrintSearchParameterTitle(u32 y, const u8 *str)
{
PrintSearchText(str, 152, y * 16 + 9);
}
static void ClearSearchParameterBoxText(void)
{
ClearSearchMenuRect(144, 8, 96, 96);
}