#include "global.h" #include "battle_dome.h" #include "battle.h" #include "battle_main.h" #include "battle_setup.h" #include "battle_tower.h" #include "frontier_util.h" #include "battle_message.h" #include "event_data.h" #include "overworld.h" #include "util.h" #include "malloc.h" #include "string_util.h" #include "random.h" #include "task.h" #include "main.h" #include "gpu_regs.h" #include "text.h" #include "bg.h" #include "window.h" #include "strings.h" #include "palette.h" #include "decompress.h" #include "party_menu.h" #include "menu.h" #include "sound.h" #include "pokemon_icon.h" #include "data.h" #include "international_string_util.h" #include "trainer_pokemon_sprites.h" #include "scanline_effect.h" #include "script_pokemon_util.h" #include "graphics.h" #include "constants/battle_dome.h" #include "constants/frontier_util.h" #include "constants/moves.h" #include "constants/pokemon.h" #include "constants/trainers.h" #include "constants/abilities.h" #include "constants/songs.h" #include "constants/battle_frontier.h" #include "constants/rgb.h" // Enough space to hold 2 match info cards worth of trainers and their parties #define NUM_INFOCARD_SPRITES ((FRONTIER_PARTY_SIZE + 1) * 4) #define NUM_INFOCARD_TRAINERS 2 // An 'Info Card' is a trainer or match information page that can be viewed on the Tourney Tree struct TourneyTreeInfoCard { u8 spriteIds[NUM_INFOCARD_SPRITES]; u8 pos; u8 tournamentIds[NUM_INFOCARD_TRAINERS]; }; struct TourneyTreeLineSection { u8 x; u8 y; u16 src; }; #define DOME_TRAINERS gSaveBlock2Ptr->frontier.domeTrainers #define DOME_MONS gSaveBlock2Ptr->frontier.domeMonIds #define tState data[0] // Task data for Task_ShowTourneyTree #define tNotInteractive data[1] #define tIsPrevTourneyTree data[4] // Task data for Task_ShowTourneyInfoCard #define tTournamentId data[1] #define tMode data[2] #define tPrevTaskId data[3] // This file's functions. static u8 GetDomeTrainerMonIvs(u16 trainerId); static void SwapDomeTrainers(int id1, int id2, u16 *statsArray); static void CalcDomeMonStats(u16 species, int level, int ivs, u8 evBits, u8 nature, int *stats); static void CreateDomeOpponentMons(u16 tournamentTrainerId); static int SelectOpponentMonsUsingPersonality(u16 tournamentTrainerId, bool8 arg1); static int SelectOpponentMonsUsingOtId(u16 tournamentTrainerId, bool8 arg1); static int GetTypeEffectivenessPoints(int move, int species, int arg2); static int SelectOpponentMonsFromParty(int *arr, bool8 arg1); static void Task_ShowTourneyInfoCard(u8 taskId); static void Task_HandleInfoCardInput(u8 taskId); static u8 Task_GetInfoCardInput(u8 taskId); static void SetFacilityTrainerAndMonPtrs(void); static int TrainerIdToTournamentId(u16 trainerId); static u16 TrainerIdOfPlayerOpponent(void); static void Task_ShowTourneyTree(u8 taskId); static void Task_HandleStaticTourneyTreeInput(u8 taskId); static void CB2_TourneyTree(void); static void VblankCb_TourneyInfoCard(void); static void DisplayMatchInfoOnCard(u8 flags, u8 matchNo); static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId); static int BufferDomeWinString(u8, u8*); static u8 GetDomeBrainTrainerPicId(void); static u8 GetDomeBrainTrainerClass(void); static void CopyDomeBrainTrainerName(u8 *str); static void CopyDomeTrainerName(u8 *str, u16 trainerId); static void HblankCb_TourneyTree(void); static void VblankCb_TourneyTree(void); static u8 UpdateTourneyTreeCursor(u8 taskId); static void DecideRoundWinners(u8 roundId); static u8 GetOpposingNPCTournamentIdByRound(u8 tournamentId, u8); static void DrawTourneyAdvancementLine(u8, u8); static void SpriteCb_HorizontalScrollArrow(struct Sprite *sprite); static void SpriteCb_VerticalScrollArrow(struct Sprite *sprite); static void InitDomeChallenge(void); static void GetDomeData(void); static void SetDomeData(void); static void BufferDomeRoundText(void); static void BufferDomeOpponentName(void); static void InitDomeOpponentParty(void); static void ShowDomeOpponentInfo(void); static void ShowDomeTourneyTree(void); static void ShowPreviousDomeTourneyTree(void); static void SetDomeOpponentId(void); static void SetDomeOpponentGraphicsId(void); static void ShowNonInteractiveDomeTourneyTree(void); static void ResolveDomeRoundWinners(void); static void SaveDomeChallenge(void); static void IncrementDomeStreaks(void); static void ResetSketchedMoves(void); static void RestoreDomePlayerPartyHeldItems(void); static void ReduceDomePlayerPartyToSelectedMons(void); static void GetPlayerSeededBeforeOpponent(void); static void BufferLastDomeWinnerName(void); static void InitRandomTourneyTreeResults(void); static void InitDomeTrainers(void); // EWRAM variables. EWRAM_DATA u32 gPlayerPartyLostHP = 0; // never read static EWRAM_DATA u32 sPlayerPartyMaxHP = 0; // never read static EWRAM_DATA struct TourneyTreeInfoCard *sInfoCard = {0}; static EWRAM_DATA u8 *sTilemapBuffer = NULL; // Each move has an array of points for different move characteristics which contribute to a tourney trainers listed battle style (see sBattleStyleThresholds) // All move points are either 1 or 0, so theyre essentially flags saying whether or not the move has that characteristic static const u8 sBattleStyleMovePoints[MOVES_COUNT][NUM_MOVE_POINT_TYPES] = { [MOVE_NONE] = {0}, [MOVE_POUND] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_KARATE_CHOP] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_DOUBLE_SLAP] = {[MOVE_POINTS_DMG] = 1}, [MOVE_COMET_PUNCH] = {[MOVE_POINTS_DMG] = 1}, [MOVE_MEGA_PUNCH] = {[MOVE_POINTS_DMG] = 1}, [MOVE_PAY_DAY] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_FIRE_PUNCH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_ICE_PUNCH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_THUNDER_PUNCH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SCRATCH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_VICE_GRIP] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_GUILLOTINE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_RAZOR_WIND] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SWORDS_DANCE] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_POPULAR] = 1}, [MOVE_CUT] = {[MOVE_POINTS_DMG] = 1}, [MOVE_GUST] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_WING_ATTACK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_WHIRLWIND] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FLY] = {[MOVE_POINTS_DMG] = 1}, [MOVE_BIND] = {[MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SLAM] = {[MOVE_POINTS_DMG] = 1}, [MOVE_VINE_WHIP] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_STOMP] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_DOUBLE_KICK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_MEGA_KICK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_JUMP_KICK] = {[MOVE_POINTS_DMG] = 1}, [MOVE_ROLLING_KICK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SAND_ATTACK] = {[MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_HEADBUTT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_HORN_ATTACK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FURY_ATTACK] = {[MOVE_POINTS_DMG] = 1}, [MOVE_HORN_DRILL] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_TACKLE] = {[MOVE_POINTS_DMG] = 1}, [MOVE_BODY_SLAM] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_WRAP] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_TAKE_DOWN] = {[MOVE_POINTS_DMG] = 1}, [MOVE_THRASH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_DOUBLE_EDGE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_TAIL_WHIP] = {[MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_POISON_STING] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_TWINEEDLE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_PIN_MISSILE] = {[MOVE_POINTS_DMG] = 1}, [MOVE_LEER] = {[MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_BITE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_GROWL] = {[MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_ROAR] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_SING] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_SUPERSONIC] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_SONIC_BOOM] = {[MOVE_POINTS_DMG] = 1}, [MOVE_DISABLE] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_ACID] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_EMBER] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_FLAMETHROWER] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_MIST] = {0}, [MOVE_WATER_GUN] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_HYDRO_PUMP] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_SURF] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_ICE_BEAM] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_BLIZZARD] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_PSYBEAM] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_BUBBLE_BEAM] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_AURORA_BEAM] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_HYPER_BEAM] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_PECK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_DRILL_PECK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SUBMISSION] = {[MOVE_POINTS_DMG] = 1}, [MOVE_LOW_KICK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_COUNTER] = {[MOVE_POINTS_DEF] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_SEISMIC_TOSS] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_STRENGTH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_ABSORB] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_MEGA_DRAIN] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_LEECH_SEED] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_STATUS] = 1}, [MOVE_GROWTH] = {[MOVE_POINTS_STAT_RAISE] = 1}, [MOVE_RAZOR_LEAF] = {[MOVE_POINTS_DMG] = 1}, [MOVE_SOLAR_BEAM] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_POISON_POWDER] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_STUN_SPORE] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_SLEEP_POWDER] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_PETAL_DANCE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_STRING_SHOT] = {[MOVE_POINTS_STAT_LOWER] = 1}, [MOVE_DRAGON_RAGE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FIRE_SPIN] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_THUNDER_SHOCK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_THUNDERBOLT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_THUNDER_WAVE] = {[MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_THUNDER] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_ROCK_THROW] = {[MOVE_POINTS_DMG] = 1}, [MOVE_EARTHQUAKE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_FISSURE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_LUCK] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_DIG] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_TOXIC] = {[MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_CONFUSION] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_PSYCHIC] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_HYPNOSIS] = {[MOVE_POINTS_COMBO] = 1}, [MOVE_MEDITATE] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_STAT_RAISE] = 1}, [MOVE_AGILITY] = {[MOVE_POINTS_STAT_RAISE] = 1}, [MOVE_QUICK_ATTACK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_RAGE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_TELEPORT] = {0}, [MOVE_NIGHT_SHADE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_MIMIC] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SCREECH] = {[MOVE_POINTS_STAT_LOWER] = 1}, [MOVE_DOUBLE_TEAM] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_DEF] = 1}, [MOVE_RECOVER] = {0}, [MOVE_HARDEN] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_DEF] = 1}, [MOVE_MINIMIZE] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_DEF] = 1}, [MOVE_SMOKESCREEN] = {[MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_DEF] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_CONFUSE_RAY] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_WITHDRAW] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_DEF] = 1}, [MOVE_DEFENSE_CURL] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_DEF] = 1}, [MOVE_BARRIER] = {[MOVE_POINTS_DEF] = 1}, [MOVE_LIGHT_SCREEN] = {[MOVE_POINTS_DEF] = 1}, [MOVE_HAZE] = {0}, [MOVE_REFLECT] = {[MOVE_POINTS_DEF] = 1}, [MOVE_FOCUS_ENERGY] = {[MOVE_POINTS_COMBO] = 1}, [MOVE_BIDE] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_METRONOME] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_MIRROR_MOVE] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_SELF_DESTRUCT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_EGG_BOMB] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_LICK] = {[MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SMOG] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SLUDGE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_BONE_CLUB] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_FIRE_BLAST] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_WATERFALL] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_CLAMP] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SWIFT] = {[MOVE_POINTS_DMG] = 1}, [MOVE_SKULL_BASH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_SPIKE_CANNON] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_CONSTRICT] = {[MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_AMNESIA] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_DEF] = 1}, [MOVE_KINESIS] = {[MOVE_POINTS_STAT_LOWER] = 1}, [MOVE_SOFT_BOILED] = {[MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_HI_JUMP_KICK] = {[MOVE_POINTS_DMG] = 1}, [MOVE_GLARE] = {[MOVE_POINTS_STAT_LOWER] = 1}, [MOVE_DREAM_EATER] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_RARE] = 1, [MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_POISON_GAS] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_BARRAGE] = {[MOVE_POINTS_DMG] = 1}, [MOVE_LEECH_LIFE] = {[MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_LOVELY_KISS] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_SKY_ATTACK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_TRANSFORM] = {[MOVE_POINTS_RARE] = 1}, [MOVE_BUBBLE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_DIZZY_PUNCH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SPORE] = {[MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FLASH] = {0}, [MOVE_PSYWAVE] = {[MOVE_POINTS_DMG] = 1}, [MOVE_SPLASH] = {[MOVE_POINTS_RARE] = 1}, [MOVE_ACID_ARMOR] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_DEF] = 1}, [MOVE_CRABHAMMER] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_EXPLOSION] = {[MOVE_POINTS_RISKY] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_FURY_SWIPES] = {[MOVE_POINTS_DMG] = 1}, [MOVE_BONEMERANG] = {[MOVE_POINTS_DMG] = 1}, [MOVE_REST] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_HEAL] = 1}, [MOVE_ROCK_SLIDE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_HYPER_FANG] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SHARPEN] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_DEF] = 1}, [MOVE_CONVERSION] = {[MOVE_POINTS_DEF] = 1}, [MOVE_TRI_ATTACK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SUPER_FANG] = {[MOVE_POINTS_DMG] = 1}, [MOVE_SLASH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SUBSTITUTE] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_DEF] = 1}, [MOVE_STRUGGLE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, // Odd that this is assigned qualities [MOVE_SKETCH] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_LUCK] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_TRIPLE_KICK] = {[MOVE_POINTS_DMG] = 1}, [MOVE_THIEF] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SPIDER_WEB] = {[MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_MIND_READER] = {[MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_NIGHTMARE] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FLAME_WHEEL] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SNORE] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_CURSE] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_FLAIL] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_CONVERSION_2] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_AEROBLAST] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_COTTON_SPORE] = {[MOVE_POINTS_STAT_LOWER] = 1}, [MOVE_REVERSAL] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SPITE] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_RISKY] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_POWDER_SNOW] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_PROTECT] = {[MOVE_POINTS_DEF] = 1, [MOVE_POINTS_POPULAR] = 1}, [MOVE_MACH_PUNCH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SCARY_FACE] = {0}, [MOVE_FAINT_ATTACK] = {[MOVE_POINTS_DMG] = 1}, [MOVE_SWEET_KISS] = {0}, [MOVE_BELLY_DRUM] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_STAT_RAISE] = 1}, [MOVE_SLUDGE_BOMB] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_MUD_SLAP] = {[MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_OCTAZOOKA] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SPIKES] = {[MOVE_POINTS_COMBO] = 1}, [MOVE_ZAP_CANNON] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_LUCK] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_FORESIGHT] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_DESTINY_BOND] = {[MOVE_POINTS_RISKY] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_PERISH_SONG] = {[MOVE_POINTS_RISKY] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_ICY_WIND] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_DETECT] = {[MOVE_POINTS_DEF] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_BONE_RUSH] = {[MOVE_POINTS_DMG] = 1}, [MOVE_LOCK_ON] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_OUTRAGE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SANDSTORM] = {0}, [MOVE_GIGA_DRAIN] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_ENDURE] = {[MOVE_POINTS_DEF] = 1}, [MOVE_CHARM] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_ROLLOUT] = {[MOVE_POINTS_DMG] = 1}, [MOVE_FALSE_SWIPE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SWAGGER] = {[MOVE_POINTS_EFFECT] = 1}, [MOVE_MILK_DRINK] = {[MOVE_POINTS_HEAL] = 1}, [MOVE_SPARK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_FURY_CUTTER] = {[MOVE_POINTS_DMG] = 1}, [MOVE_STEEL_WING] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_MEAN_LOOK] = {[MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_ATTRACT] = {[MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SLEEP_TALK] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_HEAL_BELL] = {[MOVE_POINTS_LOW_PP] = 1}, [MOVE_RETURN] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_PRESENT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_FRUSTRATION] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SAFEGUARD] = {[MOVE_POINTS_DEF] = 1}, [MOVE_PAIN_SPLIT] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SACRED_FIRE] = {[MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_MAGNITUDE] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_DYNAMIC_PUNCH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_LUCK] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_MEGAHORN] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_DRAGON_BREATH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_BATON_PASS] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_RARE] = 1}, [MOVE_ENCORE] = {[MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_PURSUIT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_RAPID_SPIN] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SWEET_SCENT] = {[MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_IRON_TAIL] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_METAL_CLAW] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_VITAL_THROW] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_MORNING_SUN] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_SYNTHESIS] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_MOONLIGHT] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_HIDDEN_POWER] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_CROSS_CHOP] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_TWISTER] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_RAIN_DANCE] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_SUNNY_DAY] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_CRUNCH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_MIRROR_COAT] = {[MOVE_POINTS_DEF] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_PSYCH_UP] = {[MOVE_POINTS_STAT_RAISE] = 1}, [MOVE_EXTREME_SPEED] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_ANCIENT_POWER] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SHADOW_BALL] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_FUTURE_SIGHT] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_DMG] = 1}, [MOVE_ROCK_SMASH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_WHIRLPOOL] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_BEAT_UP] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FAKE_OUT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_UPROAR] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_STOCKPILE] = {[MOVE_POINTS_COMBO] = 1}, [MOVE_SPIT_UP] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_SWALLOW] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_HEAL] = 1}, [MOVE_HEAT_WAVE] = {[MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_HAIL] = {0}, [MOVE_TORMENT] = {[MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FLATTER] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_WILL_O_WISP] = {[MOVE_POINTS_STATUS] = 1}, [MOVE_MEMENTO] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FACADE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FOCUS_PUNCH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_SMELLING_SALT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FOLLOW_ME] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_NATURE_POWER] = {[MOVE_POINTS_DMG] = 1}, [MOVE_CHARGE] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_TAUNT] = {[MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_HELPING_HAND] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_TRICK] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_ROLE_PLAY] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_WISH] = {[MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_ASSIST] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_INGRAIN] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_DEF] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_SUPERPOWER] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_MAGIC_COAT] = {[MOVE_POINTS_DEF] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_RECYCLE] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_REVENGE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_BRICK_BREAK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_YAWN] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_KNOCK_OFF] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_ENDEAVOR] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_ERUPTION] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_SKILL_SWAP] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_IMPRISON] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_REFRESH] = {[MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_GRUDGE] = {[MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_SNATCH] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LUCK] = 1}, [MOVE_SECRET_POWER] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_DIVE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_ARM_THRUST] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_CAMOUFLAGE] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_TAIL_GLOW] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_LUSTER_PURGE] = {[MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_MIST_BALL] = {[MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_FEATHER_DANCE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_TEETER_DANCE] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_BLAZE_KICK] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_MUD_SPORT] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_ICE_BALL] = {[MOVE_POINTS_DMG] = 1}, [MOVE_NEEDLE_ARM] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SLACK_OFF] = {[MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_HYPER_VOICE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_POISON_FANG] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_CRUSH_CLAW] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_BLAST_BURN] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_HYDRO_CANNON] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_METEOR_MASH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_ASTONISH] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_WEATHER_BALL] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_AROMATHERAPY] = {[MOVE_POINTS_LOW_PP] = 1}, [MOVE_FAKE_TEARS] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_AIR_CUTTER] = {[MOVE_POINTS_DMG] = 1}, [MOVE_OVERHEAT] = {[MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_ODOR_SLEUTH] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_ROCK_TOMB] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SILVER_WIND] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_METAL_SOUND] = {0}, [MOVE_GRASS_WHISTLE] = {0}, [MOVE_TICKLE] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_COSMIC_POWER] = {0}, [MOVE_WATER_SPOUT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_SIGNAL_BEAM] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SHADOW_PUNCH] = {[MOVE_POINTS_DMG] = 1}, [MOVE_EXTRASENSORY] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SKY_UPPERCUT] = {[MOVE_POINTS_DMG] = 1}, [MOVE_SAND_TOMB] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_SHEER_COLD] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_LUCK] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_MUDDY_WATER] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_BULLET_SEED] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_AERIAL_ACE] = {[MOVE_POINTS_DMG] = 1}, [MOVE_ICICLE_SPEAR] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_IRON_DEFENSE] = {[MOVE_POINTS_DEF] = 1}, [MOVE_BLOCK] = {[MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_HOWL] = {0}, [MOVE_DRAGON_CLAW] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_FRENZY_PLANT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_BULK_UP] = {[MOVE_POINTS_COMBO] = 1}, [MOVE_BOUNCE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_MUD_SHOT] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_POISON_TAIL] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_COVET] = {[MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_VOLT_TACKLE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1}, [MOVE_MAGICAL_LEAF] = {[MOVE_POINTS_DMG] = 1}, [MOVE_WATER_SPORT] = {[MOVE_POINTS_ACCURATE] = 1}, [MOVE_CALM_MIND] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_STAT_RAISE] = 1}, [MOVE_LEAF_BLADE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1}, [MOVE_DRAGON_DANCE] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_STAT_RAISE] = 1}, [MOVE_ROCK_BLAST] = {[MOVE_POINTS_DMG] = 1}, [MOVE_SHOCK_WAVE] = {[MOVE_POINTS_DMG] = 1}, [MOVE_WATER_PULSE] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_ACCURATE] = 1, [MOVE_POINTS_EFFECT] = 1}, [MOVE_DOOM_DESIRE] = {[MOVE_POINTS_RARE] = 1, [MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1}, [MOVE_PSYCHO_BOOST] = {[MOVE_POINTS_DMG] = 1, [MOVE_POINTS_POWERFUL] = 1, [MOVE_POINTS_STRONG] = 1, [MOVE_POINTS_LOW_PP] = 1, [MOVE_POINTS_EFFECT] = 1}, }; // This array is searched in-order to determine what battle style a tourney trainer uses. // If the sum of the points for the party's moves meets/exceeds all the point totals of an element, then they use that battle style static const u8 sBattleStyleThresholds[NUM_BATTLE_STYLES - 1][NUM_MOVE_POINT_TYPES] = { [DOME_BATTLE_STYLE_RISKY] = {[MOVE_POINTS_RISKY] = 1}, [DOME_BATTLE_STYLE_STALL] = {[MOVE_POINTS_HEAL] = 2, [MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_DEF] = 2}, [DOME_BATTLE_STYLE_VARIED] = {[MOVE_POINTS_COMBO] = 1, [MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_STATUS] = 1, [MOVE_POINTS_DEF] = 1}, [DOME_BATTLE_STYLE_COMBO_HIGH] = {[MOVE_POINTS_COMBO] = 3}, [DOME_BATTLE_STYLE_RARE_MOVES] = {[MOVE_POINTS_RARE] = 2}, [DOME_BATTLE_STYLE_RARE_MOVE] = {[MOVE_POINTS_RARE] = 1}, [DOME_BATTLE_STYLE_HP] = {[MOVE_POINTS_HEAL] = 3}, [DOME_BATTLE_STYLE_STORE_POWER] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_HEAL] = 1}, [DOME_BATTLE_STYLE_ENFEEBLE_LOW] = {[MOVE_POINTS_STAT_LOWER] = 1, [MOVE_POINTS_STATUS] = 1}, [DOME_BATTLE_STYLE_LUCK] = {[MOVE_POINTS_LUCK] = 2}, [DOME_BATTLE_STYLE_REGAL] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_DEF] = 1, [MOVE_POINTS_POPULAR] = 1, [MOVE_POINTS_STRONG] = 1}, [DOME_BATTLE_STYLE_LOW_PP] = {[MOVE_POINTS_LOW_PP] = 3}, [DOME_BATTLE_STYLE_STATUS_ATK] = {[MOVE_POINTS_STAT_RAISE] = 1, [MOVE_POINTS_STATUS] = 1}, [DOME_BATTLE_STYLE_ENDURE] = {[MOVE_POINTS_HEAL] = 2, [MOVE_POINTS_DEF] = 2}, [DOME_BATTLE_STYLE_STATUS] = {[MOVE_POINTS_STATUS] = 2}, [DOME_BATTLE_STYLE_STRAIGHTFORWARD] = {[MOVE_POINTS_ACCURATE] = 3, [MOVE_POINTS_STRONG] = 3}, [DOME_BATTLE_STYLE_AGGRESSIVE] = {[MOVE_POINTS_STRONG] = 4}, [DOME_BATTLE_STYLE_DEF] = {[MOVE_POINTS_DEF] = 3}, [DOME_BATTLE_STYLE_ENFEEBLE_HIGH] = {[MOVE_POINTS_STAT_LOWER] = 2, [MOVE_POINTS_STATUS] = 2}, // BUG: This battle style is unobtainable; DOME_BATTLE_STYLE_ENFEEBLE_LOW will always succeed before it [DOME_BATTLE_STYLE_POPULAR_POWER] = {[MOVE_POINTS_POWERFUL] = 3, [MOVE_POINTS_POPULAR] = 3}, [DOME_BATTLE_STYLE_COMBO_LOW] = {[MOVE_POINTS_COMBO] = 2}, [DOME_BATTLE_STYLE_ACCURATE] = {[MOVE_POINTS_HEAL] = 1, [MOVE_POINTS_ACCURATE] = 3}, [DOME_BATTLE_STYLE_POWERFUL] = {[MOVE_POINTS_POWERFUL] = 4}, [DOME_BATTLE_STYLE_ATK_OVER_DEF] = {[MOVE_POINTS_DMG] = 7}, [DOME_BATTLE_STYLE_DEF_OVER_ATK] = {[MOVE_POINTS_DEF] = 4}, // BUG: This battle style is unobtainable; DOME_BATTLE_STYLE_DEF will always succeed before it [DOME_BATTLE_STYLE_POPULAR_STRONG] = {[MOVE_POINTS_POPULAR] = 2, [MOVE_POINTS_STRONG] = 4}, [DOME_BATTLE_STYLE_EFFECTS] = {[MOVE_POINTS_EFFECT] = 4}, [DOME_BATTLE_STYLE_BALANCED] = {0}, // If no other thresholds are met, this battle style is used [DOME_BATTLE_STYLE_UNUSED1] = {0}, // Here below is unreachable [DOME_BATTLE_STYLE_UNUSED2] = {0}, [DOME_BATTLE_STYLE_UNUSED3] = {0}, //[DOME_BATTLE_STYLE_UNUSED4] = {0}, // Excluded here, presumably was meant to be a style just for Dome Ace Tucker }; static const u8 sUnusedArray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 253, 0, 0, 0, 0, 0, 253, 0, 0, 0, 0, 0, 253, 0, 0, 0, 0, 0, 253, 0, 0, 0, 0, 0, 253, 254, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, }; // 1st array is for cursor position (sprite id): cursor can be on a trainer info button, a match info button, or the exit/cancel button // 2nd array is for round count. For some reason this array contains an inaccessible Round 5 which is identical to Round 4 // 3rd array is movement direction (see the MOVE_DIR_* constants in UpdateTourneyTreeCursor) // The values are sprite IDs for the cursor position to move to, with 0xFF being an invalid move static const u8 sTourneyTreeCursorMovementMap[DOME_TOURNAMENT_TRAINERS_COUNT + DOME_TOURNAMENT_MATCHES_COUNT + 1][DOME_ROUNDS_COUNT + 1][4]= { [0] = {{ 7, 1, 8, 16}, { 7, 1, 8, 16}, { 7, 1, 8, 16}, { 7, 1, 8, 16}, { 7, 1, 8, 16}}, [1] = {{ 0, 2, 9, 16}, { 0, 2, 9, 16}, { 0, 2, 9, 16}, { 0, 2, 9, 16}, { 0, 2, 9, 16}}, [2] = {{ 1, 3, 10, 17}, { 1, 3, 10, 17}, { 1, 3, 10, 17}, { 1, 3, 10, 17}, { 1, 3, 10, 17}}, [3] = {{ 2, 4, 11, 17}, { 2, 4, 11, 17}, { 2, 4, 11, 17}, { 2, 4, 11, 17}, { 2, 4, 11, 17}}, [4] = {{ 3, 5, 12, 18}, { 3, 5, 12, 18}, { 3, 5, 12, 18}, { 3, 5, 12, 18}, { 3, 5, 12, 18}}, [5] = {{ 4, 6, 13, 18}, { 4, 6, 13, 18}, { 4, 6, 13, 18}, { 4, 6, 13, 18}, { 4, 6, 13, 18}}, [6] = {{ 5, 7, 14, 19}, { 5, 7, 14, 19}, { 5, 7, 14, 19}, { 5, 7, 14, 19}, { 5, 7, 14, 19}}, [7] = {{ 6, 0, 15, 19}, { 6, 0, 15, 19}, { 6, 0, 15, 19}, { 6, 0, 15, 19}, { 6, 0, 15, 19}}, [8] = {{ 31, 9, 20, 31}, { 31, 9, 20, 31}, { 31, 9, 20, 31}, { 31, 9, 20, 31}, { 31, 9, 20, 31}}, [9] = {{ 8, 10, 20, 1}, { 8, 10, 20, 1}, { 8, 10, 20, 1}, { 8, 10, 20, 1}, { 8, 10, 20, 1}}, [10] = {{ 9, 11, 21, 2}, { 9, 11, 21, 2}, { 9, 11, 21, 2}, { 9, 11, 21, 2}, { 9, 11, 21, 2}}, [11] = {{ 10, 12, 21, 3}, { 10, 12, 21, 3}, { 10, 12, 21, 3}, { 10, 12, 21, 3}, { 10, 12, 21, 3}}, [12] = {{ 11, 13, 22, 4}, { 11, 13, 22, 4}, { 11, 13, 22, 4}, { 11, 13, 22, 4}, { 11, 13, 22, 4}}, [13] = {{ 12, 14, 22, 5}, { 12, 14, 22, 5}, { 12, 14, 22, 5}, { 12, 14, 22, 5}, { 12, 14, 22, 5}}, [14] = {{ 13, 15, 23, 6}, { 13, 15, 23, 6}, { 13, 15, 23, 6}, { 13, 15, 23, 6}, { 13, 15, 23, 6}}, [15] = {{ 14, 31, 23, 7}, { 14, 31, 23, 7}, { 14, 31, 23, 7}, { 14, 31, 23, 7}, { 14, 31, 23, 7}}, [16] = {{ 19, 17, 0, 20}, { 19, 17, 0, 24}, { 19, 17, 0, 24}, { 19, 17, 0, 24}, { 19, 17, 0, 24}}, [17] = {{ 16, 18, 2, 21}, { 16, 18, 2, 24}, { 16, 18, 2, 24}, { 16, 18, 2, 24}, { 16, 18, 2, 24}}, [18] = {{ 17, 19, 4, 22}, { 17, 19, 4, 25}, { 17, 19, 4, 25}, { 17, 19, 4, 25}, { 17, 19, 4, 25}}, [19] = {{ 18, 16, 6, 23}, { 18, 16, 6, 25}, { 18, 16, 6, 25}, { 18, 16, 6, 25}, { 18, 16, 6, 25}}, [20] = {{ 23, 21, 16, 8}, { 23, 21, 26, 8}, { 23, 21, 26, 8}, { 23, 21, 26, 8}, { 23, 21, 26, 8}}, [21] = {{ 20, 22, 17, 10}, { 20, 22, 26, 10}, { 20, 22, 26, 10}, { 20, 22, 26, 10}, { 20, 22, 26, 10}}, [22] = {{ 21, 23, 18, 12}, { 21, 23, 27, 12}, { 21, 23, 27, 12}, { 21, 23, 27, 12}, { 21, 23, 27, 12}}, [23] = {{ 22, 20, 19, 14}, { 22, 20, 27, 14}, { 22, 20, 27, 14}, { 22, 20, 27, 14}, { 22, 20, 27, 14}}, [24] = {{0xFF, 0xFF, 0xFF, 0xFF}, { 25, 25, 16, 26}, { 25, 25, 16, 28}, { 25, 25, 16, 28}, { 25, 25, 16, 28}}, [25] = {{0xFF, 0xFF, 0xFF, 0xFF}, { 24, 24, 18, 27}, { 24, 24, 18, 28}, { 24, 24, 18, 28}, { 24, 24, 18, 28}}, [26] = {{0xFF, 0xFF, 0xFF, 0xFF}, { 27, 27, 24, 20}, { 27, 27, 29, 20}, { 27, 27, 29, 20}, { 27, 27, 29, 20}}, [27] = {{0xFF, 0xFF, 0xFF, 0xFF}, { 26, 26, 25, 22}, { 26, 26, 29, 22}, { 26, 26, 29, 22}, { 26, 26, 29, 22}}, [28] = {{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 24, 29}, {0xFF, 0xFF, 24, 30}, {0xFF, 0xFF, 24, 30}}, [29] = {{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 28, 26}, {0xFF, 0xFF, 30, 26}, {0xFF, 0xFF, 30, 26}}, [30] = {{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 28, 29}, {0xFF, 0xFF, 28, 29}}, [31] = {{ 15, 8, 8, 0}, { 15, 8, 8, 0}, { 15, 8, 8, 0}, { 15, 8, 8, 0}, { 15, 8, 8, 0}}, // TOURNEY_TREE_CLOSE_BUTTON }; static const struct BgTemplate sTourneyTreeBgTemplates[4] = { { .bg = 0, .charBaseIndex = 0, .mapBaseIndex = 28, .screenSize = 0, .paletteMode = 0, .priority = 0, .baseTile = 0 }, { .bg = 1, .charBaseIndex = 1, .mapBaseIndex = 29, .screenSize = 0, .paletteMode = 0, .priority = 1, .baseTile = 0 }, { .bg = 2, .charBaseIndex = 2, .mapBaseIndex = 30, .screenSize = 0, .paletteMode = 0, .priority = 2, .baseTile = 0 }, { .bg = 3, .charBaseIndex = 2, .mapBaseIndex = 31, .screenSize = 0, .paletteMode = 0, .priority = 2, .baseTile = 0 }, }; static const struct BgTemplate sInfoCardBgTemplates[4] = { { .bg = 0, .charBaseIndex = 0, .mapBaseIndex = 20, .screenSize = 3, .paletteMode = 0, .priority = 0, .baseTile = 0 }, { .bg = 1, .charBaseIndex = 1, .mapBaseIndex = 24, .screenSize = 3, .paletteMode = 0, .priority = 0, .baseTile = 0 }, { .bg = 2, .charBaseIndex = 2, .mapBaseIndex = 28, .screenSize = 3, .paletteMode = 0, .priority = 1, .baseTile = 0 }, { .bg = 3, .charBaseIndex = 2, .mapBaseIndex = 7, .screenSize = 0, .paletteMode = 0, .priority = 1, .baseTile = 0 }, }; static const struct WindowTemplate sTourneyTreeWindowTemplates[] = { { .bg = 0, .tilemapLeft = 0, .tilemapTop = 3, .width = 8, .height = 16, .paletteNum = 15, .baseBlock = 16, }, { .bg = 0, .tilemapLeft = 22, .tilemapTop = 3, .width = 8, .height = 16, .paletteNum = 15, .baseBlock = 144, }, { .bg = 0, .tilemapLeft = 8, .tilemapTop = 1, .width = 14, .height = 2, .paletteNum = 15, .baseBlock = 272, }, DUMMY_WIN_TEMPLATE, }; static const struct WindowTemplate sInfoCardWindowTemplates[] = { { .bg = 0, .tilemapLeft = 2, .tilemapTop = 2, .width = 26, .height = 2, .paletteNum = 15, .baseBlock = 1, }, { .bg = 0, .tilemapLeft = 16, .tilemapTop = 5, .width = 8, .height = 2, .paletteNum = 15, .baseBlock = 53, }, { .bg = 0, .tilemapLeft = 19, .tilemapTop = 7, .width = 9, .height = 3, .paletteNum = 15, .baseBlock = 69, }, { .bg = 0, .tilemapLeft = 16, .tilemapTop = 10, .width = 8, .height = 2, .paletteNum = 15, .baseBlock = 96, }, { .bg = 0, .tilemapLeft = 2, .tilemapTop = 12, .width = 26, .height = 7, .paletteNum = 15, .baseBlock = 112, }, { .bg = 0, .tilemapLeft = 5, .tilemapTop = 2, .width = 23, .height = 2, .paletteNum = 15, .baseBlock = 294, }, { .bg = 0, .tilemapLeft = 2, .tilemapTop = 5, .width = 8, .height = 2, .paletteNum = 15, .baseBlock = 340, }, { .bg = 0, .tilemapLeft = 20, .tilemapTop = 5, .width = 8, .height = 2, .paletteNum = 15, .baseBlock = 356, }, { .bg = 0, .tilemapLeft = 2, .tilemapTop = 16, .width = 26, .height = 2, .paletteNum = 15, .baseBlock = 372, }, { .bg = 1, .tilemapLeft = 2, .tilemapTop = 2, .width = 26, .height = 2, .paletteNum = 15, .baseBlock = 1, }, { .bg = 1, .tilemapLeft = 16, .tilemapTop = 5, .width = 8, .height = 2, .paletteNum = 15, .baseBlock = 53, }, { .bg = 1, .tilemapLeft = 19, .tilemapTop = 7, .width = 9, .height = 3, .paletteNum = 15, .baseBlock = 69, }, { .bg = 1, .tilemapLeft = 16, .tilemapTop = 10, .width = 8, .height = 2, .paletteNum = 15, .baseBlock = 96, }, { .bg = 1, .tilemapLeft = 2, .tilemapTop = 12, .width = 26, .height = 7, .paletteNum = 15, .baseBlock = 112, }, { .bg = 1, .tilemapLeft = 5, .tilemapTop = 2, .width = 23, .height = 2, .paletteNum = 15, .baseBlock = 294, }, { .bg = 1, .tilemapLeft = 2, .tilemapTop = 5, .width = 8, .height = 2, .paletteNum = 15, .baseBlock = 340, }, { .bg = 1, .tilemapLeft = 20, .tilemapTop = 5, .width = 8, .height = 2, .paletteNum = 15, .baseBlock = 356, }, { .bg = 1, .tilemapLeft = 2, .tilemapTop = 16, .width = 26, .height = 2, .paletteNum = 15, .baseBlock = 372, }, #ifdef UBFIX DUMMY_WIN_TEMPLATE, #endif }; static const struct ScanlineEffectParams sTourneyTreeScanlineEffectParams = { .dmaDest = ®_BG3CNT, .dmaControl = SCANLINE_EFFECT_DMACNT_16BIT, .initState = 1, }; static const struct CompressedSpriteSheet sTourneyTreeButtonsSpriteSheet[] = { {gDomeTourneyTreeButtons_Gfx, 0x0600, 0x0000}, {}, }; // Unused static const struct CompressedSpritePalette sTourneyTreeButtonsSpritePal[] = { {gDomeTourneyTreeButtons_Pal, 0x0000}, {}, }; static const struct OamData sOamData_TourneyTreePokeball = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(16x16), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(16x16), .tileNum = 0, .priority = 0, .paletteNum = 0, .affineParam = 0, }; // For Exit/Cancel buttons static const struct OamData sOamData_TourneyTreeCloseButton = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x16), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(32x16), .tileNum = 0, .priority = 0, .paletteNum = 1, .affineParam = 0, }; static const struct OamData sOamData_VerticalScrollArrow = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(16x8), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(16x8), .tileNum = 0, .priority = 0, .paletteNum = 2, .affineParam = 0, }; static const struct OamData sOamData_HorizontalScrollArrow = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(8x16), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(8x16), .tileNum = 0, .priority = 0, .paletteNum = 2, .affineParam = 0, }; static const union AnimCmd sSpriteAnim_TourneyTreePokeballNormal[] = { ANIMCMD_FRAME(20, 1), ANIMCMD_END, }; static const union AnimCmd sSpriteAnim_TourneyTreePokeballSelected[] = { ANIMCMD_FRAME(24, 1), ANIMCMD_END, }; static const union AnimCmd * const sSpriteAnimTable_TourneyTreePokeball[] = { sSpriteAnim_TourneyTreePokeballNormal, sSpriteAnim_TourneyTreePokeballSelected, }; // Sprite template for the pokeballs on the tourney tree that act as buttons to view a trainer/match info card static const struct SpriteTemplate sTourneyTreePokeballSpriteTemplate = { .tileTag = 0x0000, .paletteTag = TAG_NONE, .oam = &sOamData_TourneyTreePokeball, .anims = sSpriteAnimTable_TourneyTreePokeball, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const union AnimCmd sSpriteAnim_TourneyTreeCancelButtonNormal[] = { ANIMCMD_FRAME(8, 1), ANIMCMD_END, }; static const union AnimCmd sSpriteAnim_TourneyTreeCancelButtonSelected[] = { ANIMCMD_FRAME(0, 1), ANIMCMD_END, }; static const union AnimCmd * const sSpriteAnimTable_TourneyTreeCancelButton[] = { sSpriteAnim_TourneyTreeCancelButtonNormal, sSpriteAnim_TourneyTreeCancelButtonSelected, }; static const struct SpriteTemplate sCancelButtonSpriteTemplate = { .tileTag = 0x0000, .paletteTag = TAG_NONE, .oam = &sOamData_TourneyTreeCloseButton, .anims = sSpriteAnimTable_TourneyTreeCancelButton, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const union AnimCmd sSpriteAnim_TourneyTreeExitButtonNormal[] = { ANIMCMD_FRAME(40, 1), ANIMCMD_END, }; static const union AnimCmd sSpriteAnim_TourneyTreeExitButtonSelected[] = { ANIMCMD_FRAME(32, 1), ANIMCMD_END, }; static const union AnimCmd * const sSpriteAnimTable_TourneyTreeExitButton[] = { sSpriteAnim_TourneyTreeExitButtonNormal, sSpriteAnim_TourneyTreeExitButtonSelected, }; static const struct SpriteTemplate sExitButtonSpriteTemplate = { .tileTag = 0x0000, .paletteTag = TAG_NONE, .oam = &sOamData_TourneyTreeCloseButton, .anims = sSpriteAnimTable_TourneyTreeExitButton, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const union AnimCmd sSpriteAnim_UpArrow[] = { ANIMCMD_FRAME(18, 1), ANIMCMD_END, }; static const union AnimCmd sSpriteAnim_DownArrow[] = { ANIMCMD_FRAME(18, 1, .vFlip = TRUE), ANIMCMD_END, }; static const union AnimCmd sSpriteAnim_LeftArrow[] = { ANIMCMD_FRAME(16, 1, .hFlip = TRUE), ANIMCMD_END, }; static const union AnimCmd sSpriteAnim_RightArrow[] = { ANIMCMD_FRAME(16, 1), ANIMCMD_END, }; static const union AnimCmd * const sSpriteAnimTable_VerticalScrollArrow[] = { sSpriteAnim_UpArrow, sSpriteAnim_DownArrow, }; static const union AnimCmd * const sSpriteAnimTable_HorizontalScrollArrow[] = { sSpriteAnim_LeftArrow, sSpriteAnim_RightArrow, }; static const struct SpriteTemplate sHorizontalScrollArrowSpriteTemplate = { .tileTag = 0x0000, .paletteTag = TAG_NONE, .oam = &sOamData_HorizontalScrollArrow, .anims = sSpriteAnimTable_HorizontalScrollArrow, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCb_HorizontalScrollArrow }; static const struct SpriteTemplate sVerticalScrollArrowSpriteTemplate = { .tileTag = 0x0000, .paletteTag = TAG_NONE, .oam = &sOamData_VerticalScrollArrow, .anims = sSpriteAnimTable_VerticalScrollArrow, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCb_VerticalScrollArrow }; // Organized by seed starting position, i.e. seed 0 battles seed 8 first static const u8 sTourneyTreeTrainerIds[DOME_TOURNAMENT_TRAINERS_COUNT] = {0, 8, 12, 4, 7, 15, 11, 3, 2, 10, 14, 6, 5, 13, 9, 1}; static void (* const sBattleDomeFunctions[])(void) = { [BATTLE_DOME_FUNC_INIT] = InitDomeChallenge, [BATTLE_DOME_FUNC_GET_DATA] = GetDomeData, [BATTLE_DOME_FUNC_SET_DATA] = SetDomeData, [BATTLE_DOME_FUNC_GET_ROUND_TEXT] = BufferDomeRoundText, [BATTLE_DOME_FUNC_GET_OPPONENT_NAME] = BufferDomeOpponentName, [BATTLE_DOME_FUNC_INIT_OPPONENT_PARTY] = InitDomeOpponentParty, [BATTLE_DOME_FUNC_SHOW_OPPONENT_INFO] = ShowDomeOpponentInfo, [BATTLE_DOME_FUNC_SHOW_TOURNEY_TREE] = ShowDomeTourneyTree, [BATTLE_DOME_FUNC_SHOW_PREV_TOURNEY_TREE] = ShowPreviousDomeTourneyTree, [BATTLE_DOME_FUNC_SET_OPPONENT_ID] = SetDomeOpponentId, [BATTLE_DOME_FUNC_SET_OPPONENT_GFX] = SetDomeOpponentGraphicsId, [BATTLE_DOME_FUNC_SHOW_STATIC_TOURNEY_TREE] = ShowNonInteractiveDomeTourneyTree, [BATTLE_DOME_FUNC_RESOLVE_WINNERS] = ResolveDomeRoundWinners, [BATTLE_DOME_FUNC_SAVE] = SaveDomeChallenge, [BATTLE_DOME_FUNC_INCREMENT_STREAK] = IncrementDomeStreaks, [BATTLE_DOME_FUNC_SET_TRAINERS] = SetFacilityTrainerAndMonPtrs, [BATTLE_DOME_FUNC_RESET_SKETCH] = ResetSketchedMoves, [BATTLE_DOME_FUNC_RESTORE_HELD_ITEMS] = RestoreDomePlayerPartyHeldItems, [BATTLE_DOME_FUNC_REDUCE_PARTY] = ReduceDomePlayerPartyToSelectedMons, [BATTLE_DOME_FUNC_COMPARE_SEEDS] = GetPlayerSeededBeforeOpponent, [BATTLE_DOME_FUNC_GET_WINNER_NAME] = BufferLastDomeWinnerName, [BATTLE_DOME_FUNC_INIT_RESULTS_TREE] = InitRandomTourneyTreeResults, [BATTLE_DOME_FUNC_INIT_TRAINERS] = InitDomeTrainers, }; static const u32 sWinStreakFlags[][2] = { {STREAK_DOME_SINGLES_50, STREAK_DOME_SINGLES_OPEN}, {STREAK_DOME_DOUBLES_50, STREAK_DOME_DOUBLES_OPEN}, }; static const u32 sWinStreakMasks[][2] = { {~(STREAK_DOME_SINGLES_50), ~(STREAK_DOME_SINGLES_OPEN)}, {~(STREAK_DOME_DOUBLES_50), ~(STREAK_DOME_DOUBLES_OPEN)}, }; // TODO: The below two arrays probably need better names. The one below for example is only true of sIdToOpponentId[i][0] static const u8 sIdToOpponentId[DOME_TOURNAMENT_TRAINERS_COUNT][DOME_ROUNDS_COUNT] = { [0] = { 8, 0, 4, 8}, [1] = { 9, 12, 8, 0}, [2] = {10, 8, 12, 0}, [3] = {11, 4, 0, 8}, [4] = {12, 0, 4, 8}, [5] = {13, 12, 8, 0}, [6] = {14, 8, 12, 0}, [7] = {15, 4, 0, 8}, [8] = { 0, 0, 4, 8}, [9] = { 1, 12, 8, 0}, [10] = { 2, 8, 12, 0}, [11] = { 3, 4, 0, 8}, [12] = { 4, 0, 4, 8}, [13] = { 5, 12, 8, 0}, [14] = { 6, 8, 12, 0}, [15] = { 7, 4, 0, 8}, }; // sTourneyTreeTrainerIds with every other pair swapped static const u8 sTourneyTreeTrainerOpponentIds[DOME_TOURNAMENT_TRAINERS_COUNT] = { 0, 8, 4, 12, 7, 15, 3, 11, 2, 10, 6, 14, 5, 13, 1, 9 }; // The match number - 1 that a given tournament trainer will participate in for a given round static const u8 sIdToMatchNumber[DOME_TOURNAMENT_TRAINERS_COUNT][DOME_ROUNDS_COUNT] = { { 0, 8, 12, 14}, { 0, 8, 12, 14}, { 1, 8, 12, 14}, { 1, 8, 12, 14}, { 2, 9, 12, 14}, { 2, 9, 12, 14}, { 3, 9, 12, 14}, { 3, 9, 12, 14}, { 4, 10, 13, 14}, { 4, 10, 13, 14}, { 5, 10, 13, 14}, { 5, 10, 13, 14}, { 6, 11, 13, 14}, { 6, 11, 13, 14}, { 7, 11, 13, 14}, { 7, 11, 13, 14}, }; static const u8 sLastMatchCardNum[DOME_ROUNDS_COUNT] = { [DOME_ROUND1] = 23, [DOME_ROUND2] = 27, [DOME_SEMIFINAL] = 29, [DOME_FINAL] = 30 }; static const u8 sTrainerAndRoundToLastMatchCardNum[DOME_TOURNAMENT_TRAINERS_COUNT / 2][DOME_ROUNDS_COUNT] = { {16, 24, 28, 30}, {17, 24, 28, 30}, {18, 25, 28, 30}, {19, 25, 28, 30}, {20, 26, 29, 30}, {21, 26, 29, 30}, {22, 27, 29, 30}, {23, 27, 29, 30}, }; static const u8 sTournamentIdToPairedTrainerIds[DOME_TOURNAMENT_TRAINERS_COUNT] = {0, 15, 8, 7, 3, 12, 11, 4, 1, 14, 9, 6, 2, 13, 10, 5}; // The first line of text on a trainers info card. It describes their potential to win, based on their seed in the tournament tree. // Dome Ace Tucker has their own separate potential text. static const u8 *const sBattleDomePotentialTexts[DOME_TOURNAMENT_TRAINERS_COUNT + 1] = { BattleDome_Text_Potential1, // Highest potential BattleDome_Text_Potential2, BattleDome_Text_Potential3, BattleDome_Text_Potential4, BattleDome_Text_Potential5, BattleDome_Text_Potential6, BattleDome_Text_Potential7, BattleDome_Text_Potential8, BattleDome_Text_Potential9, BattleDome_Text_Potential10, BattleDome_Text_Potential11, BattleDome_Text_Potential12, BattleDome_Text_Potential13, BattleDome_Text_Potential14, BattleDome_Text_Potential15, BattleDome_Text_Potential16, // Lowest potential BattleDome_Text_PotentialDomeAceTucker, }; // The second line of text on a trainers info card. It gives information about their battle style (dependent on their party's moves). static const u8 *const sBattleDomeOpponentStyleTexts[NUM_BATTLE_STYLES] = { [DOME_BATTLE_STYLE_RISKY] = BattleDome_Text_StyleRiskDisaster, [DOME_BATTLE_STYLE_STALL] = BattleDome_Text_StyleEndureLongBattles, [DOME_BATTLE_STYLE_VARIED] = BattleDome_Text_StyleVariesTactics, [DOME_BATTLE_STYLE_COMBO_HIGH] = BattleDome_Text_StyleToughWinningPattern, [DOME_BATTLE_STYLE_RARE_MOVES] = BattleDome_Text_StyleUsesVeryRareMove, // Seems like the text for these two was swapped [DOME_BATTLE_STYLE_RARE_MOVE] = BattleDome_Text_StyleUsesStartlingMoves, // [DOME_BATTLE_STYLE_HP] = BattleDome_Text_StyleConstantlyWatchesHP, [DOME_BATTLE_STYLE_STORE_POWER] = BattleDome_Text_StyleStoresAndLoosesPower, [DOME_BATTLE_STYLE_ENFEEBLE_LOW] = BattleDome_Text_StyleEnfeeblesFoes, [DOME_BATTLE_STYLE_LUCK] = BattleDome_Text_StylePrefersLuckTactics, [DOME_BATTLE_STYLE_REGAL] = BattleDome_Text_StyleRegalAtmosphere, [DOME_BATTLE_STYLE_LOW_PP] = BattleDome_Text_StylePowerfulLowPPMoves, [DOME_BATTLE_STYLE_STATUS_ATK] = BattleDome_Text_StyleEnfeebleThenAttack, [DOME_BATTLE_STYLE_ENDURE] = BattleDome_Text_StyleBattlesWhileEnduring, [DOME_BATTLE_STYLE_STATUS] = BattleDome_Text_StyleUpsetsFoesEmotionally, [DOME_BATTLE_STYLE_STRAIGHTFORWARD] = BattleDome_Text_StyleStrongAndStraightforward, [DOME_BATTLE_STYLE_AGGRESSIVE] = BattleDome_Text_StyleAggressivelyStrongMoves, [DOME_BATTLE_STYLE_DEF] = BattleDome_Text_StyleCleverlyDodgesAttacks, [DOME_BATTLE_STYLE_ENFEEBLE_HIGH] = BattleDome_Text_StyleUsesUpsettingMoves, [DOME_BATTLE_STYLE_POPULAR_POWER] = BattleDome_Text_StyleUsesPopularMoves, [DOME_BATTLE_STYLE_COMBO_LOW] = BattleDome_Text_StyleHasPowerfulComboMoves, [DOME_BATTLE_STYLE_ACCURATE] = BattleDome_Text_StyleUsesHighProbabilityMoves, [DOME_BATTLE_STYLE_POWERFUL] = BattleDome_Text_StyleAggressivelySpectacularMoves, [DOME_BATTLE_STYLE_ATK_OVER_DEF] = BattleDome_Text_StyleEmphasizesOffenseOverDefense, [DOME_BATTLE_STYLE_DEF_OVER_ATK] = BattleDome_Text_StyleEmphasizesDefenseOverOffense, [DOME_BATTLE_STYLE_POPULAR_STRONG] = BattleDome_Text_StyleAttacksQuicklyStrongMoves, [DOME_BATTLE_STYLE_EFFECTS] = BattleDome_Text_StyleUsesAddedEffectMoves, [DOME_BATTLE_STYLE_BALANCED] = BattleDome_Text_StyleUsesBalancedMixOfMoves, [DOME_BATTLE_STYLE_UNUSED1] = BattleDome_Text_StyleSampleMessage1, [DOME_BATTLE_STYLE_UNUSED2] = BattleDome_Text_StyleSampleMessage2, [DOME_BATTLE_STYLE_UNUSED3] = BattleDome_Text_StyleSampleMessage3, [DOME_BATTLE_STYLE_UNUSED4] = BattleDome_Text_StyleSampleMessage4, }; // The third line of text on a trainers info card. It that gives information about their party's stat spread (based on their Pokémon's effort values and Nature). static const u8 *const sBattleDomeOpponentStatsTexts[] = { BattleDome_Text_EmphasizesHPAndAtk, // DOME_TEXT_TWO_GOOD_STATS and DOME_TEXT_HP start here BattleDome_Text_EmphasizesHPAndDef, BattleDome_Text_EmphasizesHPAndSpeed, BattleDome_Text_EmphasizesHPAndSpAtk, BattleDome_Text_EmphasizesHPAndSpDef, BattleDome_Text_EmphasizesAtkAndDef, // DOME_TEXT_ATK starts here BattleDome_Text_EmphasizesAtkAndSpeed, BattleDome_Text_EmphasizesAtkAndSpAtk, BattleDome_Text_EmphasizesAtkAndSpDef, BattleDome_Text_EmphasizesDefAndSpeed, // DOME_TEXT_DEF starts here BattleDome_Text_EmphasizesDefAndSpAtk, BattleDome_Text_EmphasizesDefAndSpDef, BattleDome_Text_EmphasizesSpeedAndSpAtk, // DOME_TEXT_SPEED starts here BattleDome_Text_EmphasizesSpeedAndSpDef, BattleDome_Text_EmphasizesSpAtkAndSpDef, // DOME_TEXT_SPATK starts here BattleDome_Text_EmphasizesHP, // DOME_TEXT_ONE_GOOD_STAT starts here BattleDome_Text_EmphasizesAtk, BattleDome_Text_EmphasizesDef, BattleDome_Text_EmphasizesSpeed, BattleDome_Text_EmphasizesSpAtk, BattleDome_Text_EmphasizesSpDef, BattleDome_Text_NeglectsHPAndAtk, // DOME_TEXT_TWO_BAD_STATS starts here BattleDome_Text_NeglectsHPAndDef, BattleDome_Text_NeglectsHPAndSpeed, BattleDome_Text_NeglectsHPAndSpAtk, BattleDome_Text_NeglectsHPAndSpDef, BattleDome_Text_NeglectsAtkAndDef, BattleDome_Text_NeglectsAtkAndSpeed, BattleDome_Text_NeglectsAtkAndSpAtk, BattleDome_Text_NeglectsAtkAndSpDef, BattleDome_Text_NeglectsDefAndSpeed, BattleDome_Text_NeglectsDefAndSpAtk, BattleDome_Text_NeglectsDefAndSpDef, BattleDome_Text_NeglectsSpeedAndSpAtk, BattleDome_Text_NeglectsSpeedAndSpDef, BattleDome_Text_NeglectsSpAtkAndSpDef, BattleDome_Text_NeglectsHP, // DOME_TEXT_ONE_BAD_STAT starts here BattleDome_Text_NeglectsAtk, BattleDome_Text_NeglectsDef, BattleDome_Text_NeglectsSpeed, BattleDome_Text_NeglectsSpAtk, BattleDome_Text_NeglectsSpDef, [DOME_TEXT_WELL_BALANCED] = BattleDome_Text_RaisesMonsWellBalanced, }; static const u8 sInfoTrainerMonX[FRONTIER_PARTY_SIZE] = {104, 136, 104}; static const u8 sInfoTrainerMonY[FRONTIER_PARTY_SIZE] = { 38, 62, 78}; static const u8 sSpeciesNameTextYCoords[] = {0, 4, 0}; // Offsets within sBattleDomeOpponentStatsTexts for stat combinations // SPDEF has no offset because by then all stat combinations have been reached, so it has no combination texts static const u8 sStatTextOffsets[NUM_STATS - 1] = { DOME_TEXT_HP, DOME_TEXT_ATK, DOME_TEXT_DEF, DOME_TEXT_SPEED, DOME_TEXT_SPATK }; static const u8 *const sBattleDomeMatchNumberTexts[DOME_TOURNAMENT_MATCHES_COUNT] = { BattleDome_Text_Round1Match1, BattleDome_Text_Round1Match2, BattleDome_Text_Round1Match3, BattleDome_Text_Round1Match4, BattleDome_Text_Round1Match5, BattleDome_Text_Round1Match6, BattleDome_Text_Round1Match7, BattleDome_Text_Round1Match8, BattleDome_Text_Round2Match1, BattleDome_Text_Round2Match2, BattleDome_Text_Round2Match3, BattleDome_Text_Round2Match4, BattleDome_Text_SemifinalMatch1, BattleDome_Text_SemifinalMatch2, BattleDome_Text_FinalMatch, }; static const u8 *const sBattleDomeWinTexts[] = { [DOME_TEXT_NO_WINNER_YET] = BattleDome_Text_LetTheBattleBegin, [DOME_TEXT_WON_USING_MOVE] = BattleDome_Text_TrainerWonUsingMove, [DOME_TEXT_CHAMP_USING_MOVE] = BattleDome_Text_TrainerBecameChamp, [DOME_TEXT_WON_ON_FORFEIT] = BattleDome_Text_TrainerWonByDefault, [DOME_TEXT_CHAMP_ON_FORFEIT] = BattleDome_Text_TrainerWonOutrightByDefault, [DOME_TEXT_WON_NO_MOVES] = BattleDome_Text_TrainerWonNoMoves, [DOME_TEXT_CHAMP_NO_MOVES] = BattleDome_Text_TrainerWonOutrightNoMoves, }; static const u8 sLeftTrainerMonX[FRONTIER_PARTY_SIZE] = { 96, 96, 96}; static const u8 sLeftTrainerMonY[FRONTIER_PARTY_SIZE] = { 56, 80, 104}; static const u8 sRightTrainerMonX[FRONTIER_PARTY_SIZE] = {144, 144, 144}; static const u8 sRightTrainerMonY[FRONTIER_PARTY_SIZE] = { 56, 80, 104}; // Duplicate of sTourneyTreeTrainerIds static const u8 sTourneyTreeTrainerIds2[DOME_TOURNAMENT_TRAINERS_COUNT] = {0, 8, 12, 4, 7, 15, 11, 3, 2, 10, 14, 6, 5, 13, 9, 1}; // The number of possible trainers that could be competing in a given match #define NUM_POSSIBLE_MATCH_TRAINERS(round) (DOME_TOURNAMENT_TRAINERS_COUNT / (1 << (DOME_ROUNDS_COUNT - round - 1))) // The range of tournament trainers to check as possible participants in a given match // Given by the offset in sCompetitorRangeByMatch[][0], the number of trainers in sCompetitorRangeByMatch[][1], and the round static const u8 sCompetitorRangeByMatch[DOME_TOURNAMENT_MATCHES_COUNT][3] = { { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1) * 0, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1), DOME_ROUND1}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1) * 1, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1), DOME_ROUND1}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1) * 2, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1), DOME_ROUND1}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1) * 3, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1), DOME_ROUND1}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1) * 4, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1), DOME_ROUND1}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1) * 5, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1), DOME_ROUND1}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1) * 6, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1), DOME_ROUND1}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1) * 7, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND1), DOME_ROUND1}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND2) * 0, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND2), DOME_ROUND2}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND2) * 1, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND2), DOME_ROUND2}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND2) * 2, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND2), DOME_ROUND2}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND2) * 3, NUM_POSSIBLE_MATCH_TRAINERS(DOME_ROUND2), DOME_ROUND2}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_SEMIFINAL) * 0, NUM_POSSIBLE_MATCH_TRAINERS(DOME_SEMIFINAL), DOME_SEMIFINAL}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_SEMIFINAL) * 1, NUM_POSSIBLE_MATCH_TRAINERS(DOME_SEMIFINAL), DOME_SEMIFINAL}, { NUM_POSSIBLE_MATCH_TRAINERS(DOME_FINAL) * 0, NUM_POSSIBLE_MATCH_TRAINERS(DOME_FINAL), DOME_FINAL}, }; // 1st value is the windowId (0 for left column, 1 for right column) // 2nd value is the y coord static const u8 sTrainerNamePositions[DOME_TOURNAMENT_TRAINERS_COUNT][2] = { { 0, 0}, { 1, 112}, { 1, 0}, { 0, 112}, { 0, 48}, { 1, 64}, { 1, 48}, { 0, 64}, { 0, 16}, { 1, 96}, { 1, 16}, { 0, 96}, { 0, 32}, { 1, 80}, { 1, 32}, { 0, 80}, }; // Coords for the pokeballs on the tourney tree that act as buttons to view trainer/match info static const u8 sTourneyTreePokeballCoords[DOME_TOURNAMENT_TRAINERS_COUNT + DOME_TOURNAMENT_MATCHES_COUNT][2] = { { 68, 33}, // Left side trainers { 68, 49}, { 68, 65}, { 68, 81}, { 68, 97}, { 68, 113}, { 68, 129}, { 68, 145}, {172, 33}, // Right side trainers {172, 49}, {172, 65}, {172, 81}, {172, 97}, {172, 113}, {172, 129}, {172, 145}, { 87, 41}, // Left side Round 1 matches { 87, 73}, { 87, 105}, { 87, 137}, {153, 41}, // Right side Round 1 matches {153, 73}, {153, 105}, {153, 137}, { 95, 57}, // Left side Round 2 matches { 95, 121}, {145, 57}, // Right side Round 2 matches {145, 121}, {103, 89}, // Left side semifinal match {137, 89}, // Right side semifinal match {120, 89}, // Final match }; // Each of these line sections define the position of the advancement line on the tourney tree for the victor of that round // The trainers here are numbered by tourney ID (rank/seed) and ordered according to where they start on the tourney tree #define LINESECTION_ROUND1_TRAINER1(lastSrc) \ {.src = 0x6021, .y = 0x04, .x = 0x09}, \ {.src = 0x6023, .y = 0x04, .x = 0x0a}, \ {.src = 0x6047, .y = 0x05, .x = 0x0a}, \ {.src = lastSrc, .y = 0x05, .x = 0x0b}, #define LINESECTION_ROUND1_TRAINER9(lastSrc) \ {.src = 0x6021, .y = 0x06, .x = 0x09}, \ {.src = 0x6021, .y = 0x06, .x = 0x0a}, \ {.src = 0x6027, .y = 0x05, .x = 0x0a}, \ {.src = lastSrc, .y = 0x05, .x = 0x0b}, #define LINESECTION_ROUND1_TRAINER13(lastSrc) \ {.src = 0x6021, .y = 0x08, .x = 0x09}, \ {.src = 0x6023, .y = 0x08, .x = 0x0a}, \ {.src = 0x6047, .y = 0x09, .x = 0x0a}, \ {.src = lastSrc, .y = 0x09, .x = 0x0b}, #define LINESECTION_ROUND1_TRAINER5(lastSrc) \ {.src = 0x6021, .y = 0x0a, .x = 0x09}, \ {.src = 0x6021, .y = 0x0a, .x = 0x0a}, \ {.src = 0x6027, .y = 0x09, .x = 0x0a}, \ {.src = lastSrc, .y = 0x09, .x = 0x0b}, #define LINESECTION_ROUND1_TRAINER8(lastSrc) \ {.src = 0x6021, .y = 0x0c, .x = 0x09}, \ {.src = 0x6023, .y = 0x0c, .x = 0x0a}, \ {.src = 0x6047, .y = 0x0d, .x = 0x0a}, \ {.src = lastSrc, .y = 0x0d, .x = 0x0b}, #define LINESECTION_ROUND1_TRAINER16(lastSrc) \ {.src = 0x6021, .y = 0x0e, .x = 0x09}, \ {.src = 0x6021, .y = 0x0e, .x = 0x0a}, \ {.src = 0x6027, .y = 0x0d, .x = 0x0a}, \ {.src = lastSrc, .y = 0x0d, .x = 0x0b}, #define LINESECTION_ROUND1_TRAINER12(lastSrc) \ {.src = 0x6021, .y = 0x10, .x = 0x09}, \ {.src = 0x6023, .y = 0x10, .x = 0x0a}, \ {.src = 0x6047, .y = 0x11, .x = 0x0a}, \ {.src = lastSrc, .y = 0x11, .x = 0x0b}, #define LINESECTION_ROUND1_TRAINER4(lastSrc) \ {.src = 0x602b, .y = 0x12, .x = 0x09}, \ {.src = 0x602b, .y = 0x12, .x = 0x0a}, \ {.src = 0x6027, .y = 0x11, .x = 0x0a}, \ {.src = lastSrc, .y = 0x11, .x = 0x0b}, #define LINESECTION_ROUND1_TRAINER3(lastSrc) \ {.src = 0x6021, .y = 0x04, .x = 0x14}, \ {.src = 0x6025, .y = 0x04, .x = 0x13}, \ {.src = 0x6049, .y = 0x05, .x = 0x13}, \ {.src = lastSrc, .y = 0x05, .x = 0x12}, #define LINESECTION_ROUND1_TRAINER11(lastSrc) \ {.src = 0x6021, .y = 0x06, .x = 0x14}, \ {.src = 0x6021, .y = 0x06, .x = 0x13}, \ {.src = 0x6029, .y = 0x05, .x = 0x13}, \ {.src = lastSrc, .y = 0x05, .x = 0x12}, #define LINESECTION_ROUND1_TRAINER15(lastSrc) \ {.src = 0x6021, .y = 0x08, .x = 0x14}, \ {.src = 0x6025, .y = 0x08, .x = 0x13}, \ {.src = 0x6049, .y = 0x09, .x = 0x13}, \ {.src = lastSrc, .y = 0x09, .x = 0x12}, #define LINESECTION_ROUND1_TRAINER7(lastSrc) \ {.src = 0x6021, .y = 0x0a, .x = 0x14}, \ {.src = 0x6021, .y = 0x0a, .x = 0x13}, \ {.src = 0x6029, .y = 0x09, .x = 0x13}, \ {.src = lastSrc, .y = 0x09, .x = 0x12}, #define LINESECTION_ROUND1_TRAINER6(lastSrc) \ {.src = 0x6021, .y = 0x0c, .x = 0x14}, \ {.src = 0x6025, .y = 0x0c, .x = 0x13}, \ {.src = 0x6049, .y = 0x0d, .x = 0x13}, \ {.src = lastSrc, .y = 0x0d, .x = 0x12}, #define LINESECTION_ROUND1_TRAINER14(lastSrc) \ {.src = 0x6021, .y = 0x0e, .x = 0x14}, \ {.src = 0x6021, .y = 0x0e, .x = 0x13}, \ {.src = 0x6029, .y = 0x0d, .x = 0x13}, \ {.src = lastSrc, .y = 0x0d, .x = 0x12}, #define LINESECTION_ROUND1_TRAINER10(lastSrc) \ {.src = 0x6021, .y = 0x10, .x = 0x14}, \ {.src = 0x6025, .y = 0x10, .x = 0x13}, \ {.src = 0x6049, .y = 0x11, .x = 0x13}, \ {.src = lastSrc, .y = 0x11, .x = 0x12}, #define LINESECTION_ROUND1_TRAINER2(lastSrc) \ {.src = 0x602b, .y = 0x12, .x = 0x14}, \ {.src = 0x602b, .y = 0x12, .x = 0x13}, \ {.src = 0x6029, .y = 0x11, .x = 0x13}, \ {.src = lastSrc, .y = 0x11, .x = 0x12}, #define LINESECTION_ROUND2_MATCH1(lastSrc) \ {.src = 0x6027, .y = 0x06, .x = 0x0b}, \ {.src = 0x6047, .y = 0x07, .x = 0x0b}, \ {.src = lastSrc, .y = 0x07, .x = 0x0c}, #define LINESECTION_ROUND2_MATCH2(lastSrc) \ {.src = 0x6027, .y = 0x08, .x = 0x0b}, \ {.src = 0x6027, .y = 0x07, .x = 0x0b}, \ {.src = lastSrc, .y = 0x07, .x = 0x0c}, #define LINESECTION_ROUND2_MATCH3(lastSrc) \ {.src = 0x6027, .y = 0x0e, .x = 0x0b}, \ {.src = 0x6047, .y = 0x0f, .x = 0x0b}, \ {.src = lastSrc, .y = 0x0f, .x = 0x0c}, #define LINESECTION_ROUND2_MATCH4(lastSrc) \ {.src = 0x6027, .y = 0x10, .x = 0x0b}, \ {.src = 0x6027, .y = 0x0f, .x = 0x0b}, \ {.src = lastSrc, .y = 0x0f, .x = 0x0c}, #define LINESECTION_ROUND2_MATCH5(lastSrc) \ {.src = 0x6029, .y = 0x06, .x = 0x12}, \ {.src = 0x6049, .y = 0x07, .x = 0x12}, \ {.src = lastSrc, .y = 0x07, .x = 0x11}, #define LINESECTION_ROUND2_MATCH6(lastSrc) \ {.src = 0x6029, .y = 0x08, .x = 0x12}, \ {.src = 0x6029, .y = 0x07, .x = 0x12}, \ {.src = lastSrc, .y = 0x07, .x = 0x11}, #define LINESECTION_ROUND2_MATCH7(lastSrc) \ {.src = 0x6029, .y = 0x0e, .x = 0x12}, \ {.src = 0x6049, .y = 0x0f, .x = 0x12}, \ {.src = lastSrc, .y = 0x0f, .x = 0x11}, #define LINESECTION_ROUND2_MATCH8(lastSrc) \ {.src = 0x6029, .y = 0x10, .x = 0x12}, \ {.src = 0x6029, .y = 0x0f, .x = 0x12}, \ {.src = lastSrc, .y = 0x0f, .x = 0x11}, #define LINESECTION_SEMIFINAL_TOP_LEFT \ {.src = 0x6027, .y = 0x08, .x = 0x0c}, \ {.src = 0x6027, .y = 0x09, .x = 0x0c}, \ {.src = 0x6027, .y = 0x0a, .x = 0x0c}, \ {.src = 0x603b, .y = 0x0b, .x = 0x0c}, #define LINESECTION_SEMIFINAL_BOTTOM_LEFT \ {.src = 0x6033, .y = 0x0e, .x = 0x0c}, \ {.src = 0x6032, .y = 0x0d, .x = 0x0c}, \ {.src = 0x6031, .y = 0x0c, .x = 0x0c}, \ {.src = 0x6030, .y = 0x0b, .x = 0x0c}, #define LINESECTION_SEMIFINAL_TOP_RIGHT \ {.src = 0x6029, .y = 0x08, .x = 0x11}, \ {.src = 0x6029, .y = 0x09, .x = 0x11}, \ {.src = 0x6029, .y = 0x0a, .x = 0x11}, \ {.src = 0x603c, .y = 0x0b, .x = 0x11}, #define LINESECTION_SEMIFINAL_BOTTOM_RIGHT \ {.src = 0x6038, .y = 0x0e, .x = 0x11}, \ {.src = 0x6037, .y = 0x0d, .x = 0x11}, \ {.src = 0x6036, .y = 0x0c, .x = 0x11}, \ {.src = 0x6035, .y = 0x0b, .x = 0x11}, #define LINESECTION_FINAL_LEFT \ {.src = 0x602c, .y = 0x0b, .x = 0x0d}, \ {.src = 0x602d, .y = 0x0b, .x = 0x0e}, #define LINESECTION_FINAL_RIGHT \ {.src = 0x602f, .y = 0x0b, .x = 0x10}, \ {.src = 0x602e, .y = 0x0b, .x = 0x0f}, static const struct TourneyTreeLineSection sLineSectionTrainer1Round1[] = { LINESECTION_ROUND1_TRAINER1(0x6043) }; static const struct TourneyTreeLineSection sLineSectionTrainer1Round2[] = { LINESECTION_ROUND1_TRAINER1(0x6023) LINESECTION_ROUND2_MATCH1(0x6043) }; static const struct TourneyTreeLineSection sLineSectionTrainer1Semifinal[] = { LINESECTION_ROUND1_TRAINER1(0x6023) LINESECTION_ROUND2_MATCH1(0x6023) LINESECTION_SEMIFINAL_TOP_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer1Final[] = { LINESECTION_ROUND1_TRAINER1(0x6023) LINESECTION_ROUND2_MATCH1(0x6023) LINESECTION_SEMIFINAL_TOP_LEFT LINESECTION_FINAL_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer9Round1[] = { LINESECTION_ROUND1_TRAINER9(0x6043) }; static const struct TourneyTreeLineSection sLineSectionTrainer9Round2[] = { LINESECTION_ROUND1_TRAINER9(0x6023) LINESECTION_ROUND2_MATCH1(0x6043) }; static const struct TourneyTreeLineSection sLineSectionTrainer9Semifinal[] = { LINESECTION_ROUND1_TRAINER9(0x6023) LINESECTION_ROUND2_MATCH1(0x6023) LINESECTION_SEMIFINAL_TOP_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer9Final[] = { LINESECTION_ROUND1_TRAINER9(0x6023) LINESECTION_ROUND2_MATCH1(0x6023) LINESECTION_SEMIFINAL_TOP_LEFT LINESECTION_FINAL_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer13Round1[] = { LINESECTION_ROUND1_TRAINER13(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer13Round2[] = { LINESECTION_ROUND1_TRAINER13(0x6021) LINESECTION_ROUND2_MATCH2(0x6043) }; static const struct TourneyTreeLineSection sLineSectionTrainer13Semifinal[] = { LINESECTION_ROUND1_TRAINER13(0x6021) LINESECTION_ROUND2_MATCH2(0x6023) LINESECTION_SEMIFINAL_TOP_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer13Final[] = { LINESECTION_ROUND1_TRAINER13(0x6021) LINESECTION_ROUND2_MATCH2(0x6023) LINESECTION_SEMIFINAL_TOP_LEFT LINESECTION_FINAL_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer5Round1[] = { LINESECTION_ROUND1_TRAINER5(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer5Round2[] = { LINESECTION_ROUND1_TRAINER5(0x6021) LINESECTION_ROUND2_MATCH2(0x6043) }; static const struct TourneyTreeLineSection sLineSectionTrainer5Semifinal[] = { LINESECTION_ROUND1_TRAINER5(0x6021) LINESECTION_ROUND2_MATCH2(0x6023) LINESECTION_SEMIFINAL_TOP_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer5Final[] = { LINESECTION_ROUND1_TRAINER5(0x6021) LINESECTION_ROUND2_MATCH2(0x6023) LINESECTION_SEMIFINAL_TOP_LEFT LINESECTION_FINAL_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer8Round1[] = { LINESECTION_ROUND1_TRAINER8(0x6043) }; static const struct TourneyTreeLineSection sLineSectionTrainer8Round2[] = { LINESECTION_ROUND1_TRAINER8(0x6023) LINESECTION_ROUND2_MATCH3(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer8Semifinal[] = { LINESECTION_ROUND1_TRAINER8(0x6023) LINESECTION_ROUND2_MATCH3(0x6021) LINESECTION_SEMIFINAL_BOTTOM_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer8Final[] = { LINESECTION_ROUND1_TRAINER8(0x6023) LINESECTION_ROUND2_MATCH3(0x6021) LINESECTION_SEMIFINAL_BOTTOM_LEFT LINESECTION_FINAL_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer16Round1[] = { LINESECTION_ROUND1_TRAINER16(0x6043) }; static const struct TourneyTreeLineSection sLineSectionTrainer16Round2[] = { LINESECTION_ROUND1_TRAINER16(0x6023) LINESECTION_ROUND2_MATCH3(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer16Semifinal[] = { LINESECTION_ROUND1_TRAINER16(0x6023) LINESECTION_ROUND2_MATCH3(0x6021) LINESECTION_SEMIFINAL_BOTTOM_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer16Final[] = { LINESECTION_ROUND1_TRAINER16(0x6023) LINESECTION_ROUND2_MATCH3(0x6021) LINESECTION_SEMIFINAL_BOTTOM_LEFT LINESECTION_FINAL_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer12Round1[] = { LINESECTION_ROUND1_TRAINER12(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer12Round2[] = { LINESECTION_ROUND1_TRAINER12(0x6021) LINESECTION_ROUND2_MATCH4(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer12Semifinal[] = { LINESECTION_ROUND1_TRAINER12(0x6021) LINESECTION_ROUND2_MATCH4(0x6021) LINESECTION_SEMIFINAL_BOTTOM_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer12Final[] = { LINESECTION_ROUND1_TRAINER12(0x6021) LINESECTION_ROUND2_MATCH4(0x6021) LINESECTION_SEMIFINAL_BOTTOM_LEFT LINESECTION_FINAL_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer4Round1[] = { LINESECTION_ROUND1_TRAINER4(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer4Round2[] = { LINESECTION_ROUND1_TRAINER4(0x6021) LINESECTION_ROUND2_MATCH4(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer4Semifinal[] = { LINESECTION_ROUND1_TRAINER4(0x6021) LINESECTION_ROUND2_MATCH4(0x6021) LINESECTION_SEMIFINAL_BOTTOM_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer4Final[] = { LINESECTION_ROUND1_TRAINER4(0x6021) LINESECTION_ROUND2_MATCH4(0x6021) LINESECTION_SEMIFINAL_BOTTOM_LEFT LINESECTION_FINAL_LEFT }; static const struct TourneyTreeLineSection sLineSectionTrainer3Round1[] = { LINESECTION_ROUND1_TRAINER3(0x6045) }; static const struct TourneyTreeLineSection sLineSectionTrainer3Round2[] = { LINESECTION_ROUND1_TRAINER3(0x6025) LINESECTION_ROUND2_MATCH5(0x6045) }; static const struct TourneyTreeLineSection sLineSectionTrainer3Semifinal[] = { LINESECTION_ROUND1_TRAINER3(0x6025) LINESECTION_ROUND2_MATCH5(0x6025) LINESECTION_SEMIFINAL_TOP_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer3Final[] = { LINESECTION_ROUND1_TRAINER3(0x6025) LINESECTION_ROUND2_MATCH5(0x6025) LINESECTION_SEMIFINAL_TOP_RIGHT LINESECTION_FINAL_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer11Round1[] = { LINESECTION_ROUND1_TRAINER11(0x6045) }; static const struct TourneyTreeLineSection sLineSectionTrainer11Round2[] = { LINESECTION_ROUND1_TRAINER11(0x6025) LINESECTION_ROUND2_MATCH5(0x6045) }; static const struct TourneyTreeLineSection sLineSectionTrainer11Semifinal[] = { LINESECTION_ROUND1_TRAINER11(0x6025) LINESECTION_ROUND2_MATCH5(0x6025) LINESECTION_SEMIFINAL_TOP_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer11Final[] = { LINESECTION_ROUND1_TRAINER11(0x6025) LINESECTION_ROUND2_MATCH5(0x6025) LINESECTION_SEMIFINAL_TOP_RIGHT LINESECTION_FINAL_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer15Round1[] = { LINESECTION_ROUND1_TRAINER15(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer15Round2[] = { LINESECTION_ROUND1_TRAINER15(0x6021) LINESECTION_ROUND2_MATCH6(0x6045) }; static const struct TourneyTreeLineSection sLineSectionTrainer15Semifinal[] = { LINESECTION_ROUND1_TRAINER15(0x6021) LINESECTION_ROUND2_MATCH6(0x6025) LINESECTION_SEMIFINAL_TOP_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer15Final[] = { LINESECTION_ROUND1_TRAINER15(0x6021) LINESECTION_ROUND2_MATCH6(0x6025) LINESECTION_SEMIFINAL_TOP_RIGHT LINESECTION_FINAL_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer7Round1[] = { LINESECTION_ROUND1_TRAINER7(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer7Round2[] = { LINESECTION_ROUND1_TRAINER7(0x6021) LINESECTION_ROUND2_MATCH6(0x6045) }; static const struct TourneyTreeLineSection sLineSectionTrainer7Semifinal[] = { LINESECTION_ROUND1_TRAINER7(0x6021) LINESECTION_ROUND2_MATCH6(0x6025) LINESECTION_SEMIFINAL_TOP_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer7Final[] = { LINESECTION_ROUND1_TRAINER7(0x6021) LINESECTION_ROUND2_MATCH6(0x6025) LINESECTION_SEMIFINAL_TOP_RIGHT LINESECTION_FINAL_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer6Round1[] = { LINESECTION_ROUND1_TRAINER6(0x6045) }; static const struct TourneyTreeLineSection sLineSectionTrainer6Round2[] = { LINESECTION_ROUND1_TRAINER6(0x6025) LINESECTION_ROUND2_MATCH7(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer6Semifinal[] = { LINESECTION_ROUND1_TRAINER6(0x6025) LINESECTION_ROUND2_MATCH7(0x6021) LINESECTION_SEMIFINAL_BOTTOM_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer6Final[] = { LINESECTION_ROUND1_TRAINER6(0x6025) LINESECTION_ROUND2_MATCH7(0x6021) LINESECTION_SEMIFINAL_BOTTOM_RIGHT LINESECTION_FINAL_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer14Round1[] = { LINESECTION_ROUND1_TRAINER14(0x6045) }; static const struct TourneyTreeLineSection sLineSectionTrainer14Round2[] = { LINESECTION_ROUND1_TRAINER14(0x6025) LINESECTION_ROUND2_MATCH7(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer14Semifinal[] = { LINESECTION_ROUND1_TRAINER14(0x6025) LINESECTION_ROUND2_MATCH7(0x6021) LINESECTION_SEMIFINAL_BOTTOM_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer14Final[] = { LINESECTION_ROUND1_TRAINER14(0x6025) LINESECTION_ROUND2_MATCH7(0x6021) LINESECTION_SEMIFINAL_BOTTOM_RIGHT LINESECTION_FINAL_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer10Round1[] = { LINESECTION_ROUND1_TRAINER10(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer10Round2[] = { LINESECTION_ROUND1_TRAINER10(0x6021) LINESECTION_ROUND2_MATCH8(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer10Semifinal[] = { LINESECTION_ROUND1_TRAINER10(0x6021) LINESECTION_ROUND2_MATCH8(0x6021) LINESECTION_SEMIFINAL_BOTTOM_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer10Final[] = { LINESECTION_ROUND1_TRAINER10(0x6021) LINESECTION_ROUND2_MATCH8(0x6021) LINESECTION_SEMIFINAL_BOTTOM_RIGHT LINESECTION_FINAL_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer2Round1[] = { LINESECTION_ROUND1_TRAINER2(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer2Round2[] = { LINESECTION_ROUND1_TRAINER2(0x6021) LINESECTION_ROUND2_MATCH8(0x6021) }; static const struct TourneyTreeLineSection sLineSectionTrainer2Semifinal[] = { LINESECTION_ROUND1_TRAINER2(0x6021) LINESECTION_ROUND2_MATCH8(0x6021) LINESECTION_SEMIFINAL_BOTTOM_RIGHT }; static const struct TourneyTreeLineSection sLineSectionTrainer2Final[] = { LINESECTION_ROUND1_TRAINER2(0x6021) LINESECTION_ROUND2_MATCH8(0x6021) LINESECTION_SEMIFINAL_BOTTOM_RIGHT LINESECTION_FINAL_RIGHT }; static const struct TourneyTreeLineSection *const sTourneyTreeLineSections[DOME_TOURNAMENT_TRAINERS_COUNT][DOME_ROUNDS_COUNT] = { {sLineSectionTrainer1Round1, sLineSectionTrainer1Round2, sLineSectionTrainer1Semifinal, sLineSectionTrainer1Final}, {sLineSectionTrainer2Round1, sLineSectionTrainer2Round2, sLineSectionTrainer2Semifinal, sLineSectionTrainer2Final}, {sLineSectionTrainer3Round1, sLineSectionTrainer3Round2, sLineSectionTrainer3Semifinal, sLineSectionTrainer3Final}, {sLineSectionTrainer4Round1, sLineSectionTrainer4Round2, sLineSectionTrainer4Semifinal, sLineSectionTrainer4Final}, {sLineSectionTrainer5Round1, sLineSectionTrainer5Round2, sLineSectionTrainer5Semifinal, sLineSectionTrainer5Final}, {sLineSectionTrainer6Round1, sLineSectionTrainer6Round2, sLineSectionTrainer6Semifinal, sLineSectionTrainer6Final}, {sLineSectionTrainer7Round1, sLineSectionTrainer7Round2, sLineSectionTrainer7Semifinal, sLineSectionTrainer7Final}, {sLineSectionTrainer8Round1, sLineSectionTrainer8Round2, sLineSectionTrainer8Semifinal, sLineSectionTrainer8Final}, {sLineSectionTrainer9Round1, sLineSectionTrainer9Round2, sLineSectionTrainer9Semifinal, sLineSectionTrainer9Final}, {sLineSectionTrainer10Round1, sLineSectionTrainer10Round2, sLineSectionTrainer10Semifinal, sLineSectionTrainer10Final}, {sLineSectionTrainer11Round1, sLineSectionTrainer11Round2, sLineSectionTrainer11Semifinal, sLineSectionTrainer11Final}, {sLineSectionTrainer12Round1, sLineSectionTrainer12Round2, sLineSectionTrainer12Semifinal, sLineSectionTrainer12Final}, {sLineSectionTrainer13Round1, sLineSectionTrainer13Round2, sLineSectionTrainer13Semifinal, sLineSectionTrainer13Final}, {sLineSectionTrainer14Round1, sLineSectionTrainer14Round2, sLineSectionTrainer14Semifinal, sLineSectionTrainer14Final}, {sLineSectionTrainer15Round1, sLineSectionTrainer15Round2, sLineSectionTrainer15Semifinal, sLineSectionTrainer15Final}, {sLineSectionTrainer16Round1, sLineSectionTrainer16Round2, sLineSectionTrainer16Semifinal, sLineSectionTrainer16Final}, }; static const u8 sTourneyTreeLineSectionArrayCounts[DOME_TOURNAMENT_TRAINERS_COUNT][DOME_ROUNDS_COUNT] = { {ARRAY_COUNT(sLineSectionTrainer1Round1), ARRAY_COUNT(sLineSectionTrainer1Round2), ARRAY_COUNT(sLineSectionTrainer1Semifinal), ARRAY_COUNT(sLineSectionTrainer1Final)}, {ARRAY_COUNT(sLineSectionTrainer2Round1), ARRAY_COUNT(sLineSectionTrainer2Round2), ARRAY_COUNT(sLineSectionTrainer2Semifinal), ARRAY_COUNT(sLineSectionTrainer2Final)}, {ARRAY_COUNT(sLineSectionTrainer3Round1), ARRAY_COUNT(sLineSectionTrainer3Round2), ARRAY_COUNT(sLineSectionTrainer3Semifinal), ARRAY_COUNT(sLineSectionTrainer3Final)}, {ARRAY_COUNT(sLineSectionTrainer4Round1), ARRAY_COUNT(sLineSectionTrainer4Round2), ARRAY_COUNT(sLineSectionTrainer4Semifinal), ARRAY_COUNT(sLineSectionTrainer4Final)}, {ARRAY_COUNT(sLineSectionTrainer5Round1), ARRAY_COUNT(sLineSectionTrainer5Round2), ARRAY_COUNT(sLineSectionTrainer5Semifinal), ARRAY_COUNT(sLineSectionTrainer5Final)}, {ARRAY_COUNT(sLineSectionTrainer6Round1), ARRAY_COUNT(sLineSectionTrainer6Round2), ARRAY_COUNT(sLineSectionTrainer6Semifinal), ARRAY_COUNT(sLineSectionTrainer6Final)}, {ARRAY_COUNT(sLineSectionTrainer7Round1), ARRAY_COUNT(sLineSectionTrainer7Round2), ARRAY_COUNT(sLineSectionTrainer7Semifinal), ARRAY_COUNT(sLineSectionTrainer7Final)}, {ARRAY_COUNT(sLineSectionTrainer8Round1), ARRAY_COUNT(sLineSectionTrainer8Round2), ARRAY_COUNT(sLineSectionTrainer8Semifinal), ARRAY_COUNT(sLineSectionTrainer8Final)}, {ARRAY_COUNT(sLineSectionTrainer9Round1), ARRAY_COUNT(sLineSectionTrainer9Round2), ARRAY_COUNT(sLineSectionTrainer9Semifinal), ARRAY_COUNT(sLineSectionTrainer9Final)}, {ARRAY_COUNT(sLineSectionTrainer10Round1), ARRAY_COUNT(sLineSectionTrainer10Round2), ARRAY_COUNT(sLineSectionTrainer10Semifinal), ARRAY_COUNT(sLineSectionTrainer10Final)}, {ARRAY_COUNT(sLineSectionTrainer11Round1), ARRAY_COUNT(sLineSectionTrainer11Round2), ARRAY_COUNT(sLineSectionTrainer11Semifinal), ARRAY_COUNT(sLineSectionTrainer11Final)}, {ARRAY_COUNT(sLineSectionTrainer12Round1), ARRAY_COUNT(sLineSectionTrainer12Round2), ARRAY_COUNT(sLineSectionTrainer12Semifinal), ARRAY_COUNT(sLineSectionTrainer12Final)}, {ARRAY_COUNT(sLineSectionTrainer13Round1), ARRAY_COUNT(sLineSectionTrainer13Round2), ARRAY_COUNT(sLineSectionTrainer13Semifinal), ARRAY_COUNT(sLineSectionTrainer13Final)}, {ARRAY_COUNT(sLineSectionTrainer14Round1), ARRAY_COUNT(sLineSectionTrainer14Round2), ARRAY_COUNT(sLineSectionTrainer14Semifinal), ARRAY_COUNT(sLineSectionTrainer14Final)}, {ARRAY_COUNT(sLineSectionTrainer15Round1), ARRAY_COUNT(sLineSectionTrainer15Round2), ARRAY_COUNT(sLineSectionTrainer15Semifinal), ARRAY_COUNT(sLineSectionTrainer15Final)}, {ARRAY_COUNT(sLineSectionTrainer16Round1), ARRAY_COUNT(sLineSectionTrainer16Round2), ARRAY_COUNT(sLineSectionTrainer16Semifinal), ARRAY_COUNT(sLineSectionTrainer16Final)}, }; // code void CallBattleDomeFunction(void) { sBattleDomeFunctions[gSpecialVar_0x8004](); } static void InitDomeChallenge(void) { u32 lvlMode = gSaveBlock2Ptr->frontier.lvlMode; u32 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE); gSaveBlock2Ptr->frontier.challengeStatus = 0; gSaveBlock2Ptr->frontier.curChallengeBattleNum = 0; gSaveBlock2Ptr->frontier.challengePaused = FALSE; gSaveBlock2Ptr->frontier.disableRecordBattle = FALSE; if (!(gSaveBlock2Ptr->frontier.winStreakActiveFlags & sWinStreakFlags[battleMode][lvlMode])) gSaveBlock2Ptr->frontier.domeWinStreaks[battleMode][lvlMode] = 0; SetDynamicWarp(0, gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum, WARP_ID_NONE); gTrainerBattleOpponent_A = 0; } static void GetDomeData(void) { u32 lvlMode = gSaveBlock2Ptr->frontier.lvlMode; u32 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE); switch (gSpecialVar_0x8005) { case DOME_DATA_WIN_STREAK: gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeWinStreaks[battleMode][lvlMode]; break; case DOME_DATA_WIN_STREAK_ACTIVE: gSpecialVar_Result = ((gSaveBlock2Ptr->frontier.winStreakActiveFlags & sWinStreakFlags[battleMode][lvlMode]) != 0); break; case DOME_DATA_ATTEMPTED_SINGLES_50: gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeAttemptedSingles50; break; case DOME_DATA_ATTEMPTED_SINGLES_OPEN: gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeAttemptedSinglesOpen; break; case DOME_DATA_HAS_WON_SINGLES_50: gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeHasWonSingles50; break; case DOME_DATA_HAS_WON_SINGLES_OPEN: gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeHasWonSinglesOpen; break; case DOME_DATA_ATTEMPTED_CHALLENGE: if (VarGet(VAR_FRONTIER_BATTLE_MODE) == FRONTIER_MODE_DOUBLES) { if (lvlMode != FRONTIER_LVL_50) gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeAttemptedDoublesOpen; else gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeAttemptedDoubles50; } else { if (lvlMode != FRONTIER_LVL_50) gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeAttemptedSinglesOpen; else gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeAttemptedSingles50; } break; case DOME_DATA_HAS_WON_CHALLENGE: if (VarGet(VAR_FRONTIER_BATTLE_MODE) == FRONTIER_MODE_DOUBLES) { if (lvlMode != FRONTIER_LVL_50) gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeHasWonDoublesOpen; else gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeHasWonDoubles50; } else { if (lvlMode != FRONTIER_LVL_50) gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeHasWonSinglesOpen; else gSpecialVar_Result = gSaveBlock2Ptr->frontier.domeHasWonSingles50; } break; case DOME_DATA_SELECTED_MONS: ClearSelectedPartyOrder(); gSelectedOrderFromParty[0] = gSaveBlock2Ptr->frontier.selectedPartyMons[3]; gSelectedOrderFromParty[1] = gSaveBlock2Ptr->frontier.selectedPartyMons[3] >> 8; break; case DOME_DATA_PREV_TOURNEY_TYPE: gSpecialVar_Result = (gSaveBlock2Ptr->frontier.domeLvlMode * 2) - 3 + gSaveBlock2Ptr->frontier.domeBattleMode; break; } } static void SetDomeData(void) { u32 lvlMode = gSaveBlock2Ptr->frontier.lvlMode; u32 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE); switch (gSpecialVar_0x8005) { case DOME_DATA_WIN_STREAK: gSaveBlock2Ptr->frontier.domeWinStreaks[battleMode][lvlMode] = gSpecialVar_0x8006; break; case DOME_DATA_WIN_STREAK_ACTIVE: if (gSpecialVar_0x8006) gSaveBlock2Ptr->frontier.winStreakActiveFlags |= sWinStreakFlags[battleMode][lvlMode]; else gSaveBlock2Ptr->frontier.winStreakActiveFlags &= sWinStreakMasks[battleMode][lvlMode]; break; case DOME_DATA_ATTEMPTED_SINGLES_50: gSaveBlock2Ptr->frontier.domeAttemptedSingles50 = gSpecialVar_0x8006; break; case DOME_DATA_ATTEMPTED_SINGLES_OPEN: gSaveBlock2Ptr->frontier.domeAttemptedSinglesOpen = gSpecialVar_0x8006; break; case DOME_DATA_HAS_WON_SINGLES_50: gSaveBlock2Ptr->frontier.domeHasWonSingles50 = gSpecialVar_0x8006; break; case DOME_DATA_HAS_WON_SINGLES_OPEN: gSaveBlock2Ptr->frontier.domeHasWonSinglesOpen = gSpecialVar_0x8006; break; case DOME_DATA_ATTEMPTED_CHALLENGE: if (VarGet(VAR_FRONTIER_BATTLE_MODE) == FRONTIER_MODE_DOUBLES) { if (lvlMode != FRONTIER_LVL_50) gSaveBlock2Ptr->frontier.domeAttemptedDoublesOpen = gSpecialVar_0x8006; else gSaveBlock2Ptr->frontier.domeAttemptedDoubles50 = gSpecialVar_0x8006; } else { if (lvlMode != FRONTIER_LVL_50) gSaveBlock2Ptr->frontier.domeAttemptedSinglesOpen = gSpecialVar_0x8006; else gSaveBlock2Ptr->frontier.domeAttemptedSingles50 = gSpecialVar_0x8006; } break; case DOME_DATA_HAS_WON_CHALLENGE: if (VarGet(VAR_FRONTIER_BATTLE_MODE) == FRONTIER_MODE_DOUBLES) { if (lvlMode != FRONTIER_LVL_50) gSaveBlock2Ptr->frontier.domeHasWonDoublesOpen = gSpecialVar_0x8006; else gSaveBlock2Ptr->frontier.domeHasWonDoubles50 = gSpecialVar_0x8006; } else { if (lvlMode != FRONTIER_LVL_50) gSaveBlock2Ptr->frontier.domeHasWonSinglesOpen = gSpecialVar_0x8006; else gSaveBlock2Ptr->frontier.domeHasWonSingles50 = gSpecialVar_0x8006; } break; case DOME_DATA_SELECTED_MONS: gSaveBlock2Ptr->frontier.selectedPartyMons[3] = T1_READ_16(gSelectedOrderFromParty); break; } } static void InitDomeTrainers(void) { int i, j, k; int monLevel; int species[FRONTIER_PARTY_SIZE]; int monTypesBits, monTypesCount; int trainerId; int monId; u16 *rankingScores; int *statValues; u8 ivs = 0; species[0] = 0; species[1] = 0; species[2] = 0; rankingScores = AllocZeroed(sizeof(u16) * DOME_TOURNAMENT_TRAINERS_COUNT); statValues = AllocZeroed(sizeof(int) * NUM_STATS); gSaveBlock2Ptr->frontier.domeLvlMode = gSaveBlock2Ptr->frontier.lvlMode + 1; gSaveBlock2Ptr->frontier.domeBattleMode = VarGet(VAR_FRONTIER_BATTLE_MODE) + 1; DOME_TRAINERS[0].trainerId = TRAINER_PLAYER; DOME_TRAINERS[0].isEliminated = FALSE; DOME_TRAINERS[0].eliminatedAt = 0; DOME_TRAINERS[0].forfeited = FALSE; // Store the data used to display party information on the player's tourney page for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { DOME_MONS[0][i] = GetMonData(&gPlayerParty[gSaveBlock2Ptr->frontier.selectedPartyMons[i] - 1], MON_DATA_SPECIES, NULL); for (j = 0; j < MAX_MON_MOVES; j++) gSaveBlock2Ptr->frontier.domePlayerPartyData[i].moves[j] = GetMonData(&gPlayerParty[gSaveBlock2Ptr->frontier.selectedPartyMons[i] - 1], MON_DATA_MOVE1 + j, NULL); for (j = 0; j < NUM_STATS; j++) gSaveBlock2Ptr->frontier.domePlayerPartyData[i].evs[j] = GetMonData(&gPlayerParty[gSaveBlock2Ptr->frontier.selectedPartyMons[i] - 1], MON_DATA_HP_EV + j, NULL); gSaveBlock2Ptr->frontier.domePlayerPartyData[i].nature = GetNature(&gPlayerParty[gSaveBlock2Ptr->frontier.selectedPartyMons[i] - 1]); } // Populate the tourney roster with random frontier trainers (dependent on streak) for (i = 1; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { // Choose trainer. First 5/16 trainers are easier than the rest if (i > 5) { do { trainerId = GetRandomScaledFrontierTrainerId(GetCurrentFacilityWinStreak(), 0); for (j = 1; j < i; j++) { if (DOME_TRAINERS[j].trainerId == trainerId) break; } } while (j != i); DOME_TRAINERS[i].trainerId = trainerId; } else { do { trainerId = GetRandomScaledFrontierTrainerId(GetCurrentFacilityWinStreak() + 1, 0); for (j = 1; j < i; j++) { if (DOME_TRAINERS[j].trainerId == trainerId) break; } } while (j != i); DOME_TRAINERS[i].trainerId = trainerId; } // Choose party for (j = 0; j < FRONTIER_PARTY_SIZE; j++) { do { monId = GetRandomFrontierMonFromSet(trainerId); for (k = 0; k < j; k++) { // Make sure the mon is valid. int alreadySelectedMonId = DOME_MONS[i][k]; if (alreadySelectedMonId == monId || species[0] == gFacilityTrainerMons[monId].species || species[1] == gFacilityTrainerMons[monId].species || gFacilityTrainerMons[alreadySelectedMonId].itemTableId == gFacilityTrainerMons[monId].itemTableId) break; } } while (k != j); DOME_MONS[i][j] = monId; species[j] = gFacilityTrainerMons[monId].species; } DOME_TRAINERS[i].isEliminated = FALSE; DOME_TRAINERS[i].eliminatedAt = 0; DOME_TRAINERS[i].forfeited = FALSE; } // rankingScores is used to determine the seed (ranking) of the trainers // rankingScores[0] is for the player, rankingScores[1-15] are for the opponent trainers // Calculate player's ranking score monTypesBits = 0; rankingScores[0] = 0; for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { // trainerId var re-used here as index of selected mons trainerId = gSaveBlock2Ptr->frontier.selectedPartyMons[i] - 1; rankingScores[0] += GetMonData(&gPlayerParty[trainerId], MON_DATA_ATK, NULL); rankingScores[0] += GetMonData(&gPlayerParty[trainerId], MON_DATA_DEF, NULL); rankingScores[0] += GetMonData(&gPlayerParty[trainerId], MON_DATA_SPATK, NULL); rankingScores[0] += GetMonData(&gPlayerParty[trainerId], MON_DATA_SPDEF, NULL); rankingScores[0] += GetMonData(&gPlayerParty[trainerId], MON_DATA_SPEED, NULL); rankingScores[0] += GetMonData(&gPlayerParty[trainerId], MON_DATA_MAX_HP, NULL); monTypesBits |= gBitTable[gBaseStats[GetMonData(&gPlayerParty[trainerId], MON_DATA_SPECIES, NULL)].type1]; monTypesBits |= gBitTable[gBaseStats[GetMonData(&gPlayerParty[trainerId], MON_DATA_SPECIES, NULL)].type2]; } // Count the number of types in the players party, to factor into the ranking for (monTypesCount = 0, j = 0; j < 32; j++) { if (monTypesBits & 1) monTypesCount++; monTypesBits >>= 1; } monLevel = SetFacilityPtrsGetLevel(); rankingScores[0] += (monTypesCount * monLevel) / 20; // Calculate rankingScores for the opponent trainers for (i = 1; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { monTypesBits = 0; rankingScores[i] = 0; ivs = GetDomeTrainerMonIvs(DOME_TRAINERS[i].trainerId); for (j = 0; j < FRONTIER_PARTY_SIZE; j++) { CalcDomeMonStats(gFacilityTrainerMons[DOME_MONS[i][j]].species, monLevel, ivs, gFacilityTrainerMons[DOME_MONS[i][j]].evSpread, gFacilityTrainerMons[DOME_MONS[i][j]].nature, statValues); rankingScores[i] += statValues[STAT_ATK]; rankingScores[i] += statValues[STAT_DEF]; rankingScores[i] += statValues[STAT_SPATK]; rankingScores[i] += statValues[STAT_SPDEF]; rankingScores[i] += statValues[STAT_SPEED]; rankingScores[i] += statValues[STAT_HP]; monTypesBits |= gBitTable[gBaseStats[gFacilityTrainerMons[DOME_MONS[i][j]].species].type1]; monTypesBits |= gBitTable[gBaseStats[gFacilityTrainerMons[DOME_MONS[i][j]].species].type2]; } for (monTypesCount = 0, j = 0; j < 32; j++) { if (monTypesBits & 1) monTypesCount++; monTypesBits >>= 1; } rankingScores[i] += (monTypesCount * monLevel) / 20; } // Seed tourney trainers according to their ranking for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT - 1; i++) { for (j = i + 1; j < DOME_TOURNAMENT_TRAINERS_COUNT; j++) { if (rankingScores[i] < rankingScores[j]) { SwapDomeTrainers(i, j, rankingScores); } else { if (rankingScores[i] == rankingScores[j]) { if (DOME_TRAINERS[j].trainerId == TRAINER_PLAYER) SwapDomeTrainers(i, j, rankingScores); else if (DOME_TRAINERS[i].trainerId > DOME_TRAINERS[j].trainerId) SwapDomeTrainers(i, j, rankingScores); } } } } // Add Frontier Brain to the tourney if they should be fought at the end of it if (GetFrontierBrainStatus() != FRONTIER_BRAIN_NOT_READY) { for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { if (DOME_TRAINERS[i].trainerId == TRAINER_PLAYER) break; } if (sTrainerNamePositions[i][0] != 0) { j = 0; DOME_TRAINERS[j].trainerId = TRAINER_FRONTIER_BRAIN; } else { j = 1; DOME_TRAINERS[j].trainerId = TRAINER_FRONTIER_BRAIN; } for (i = 0; i < FRONTIER_PARTY_SIZE; i++) DOME_MONS[j][i] = GetFrontierBrainMonSpecies(i); } Free(rankingScores); Free(statValues); } #define CALC_STAT(base, statIndex) \ { \ u8 baseStat = gBaseStats[species].base; \ stats[statIndex] = (((2 * baseStat + ivs + evs[statIndex] / 4) * level) / 100) + 5; \ stats[statIndex] = (u8) ModifyStatByNature(nature, stats[statIndex], statIndex); \ } static void CalcDomeMonStats(u16 species, int level, int ivs, u8 evBits, u8 nature, int *stats) { int i, count; u8 bits; u16 resultingEvs; int evs[NUM_STATS]; count = 0, bits = evBits; for (i = 0; i < NUM_STATS; bits >>= 1, i++) { if (bits & 1) count++; } resultingEvs = MAX_TOTAL_EVS / count; for (i = 0; i < NUM_STATS; bits <<= 1, i++) { evs[i] = 0; if (evBits & bits) evs[i] = resultingEvs; } if (species == SPECIES_SHEDINJA) { stats[STAT_HP] = 1; } else { int n = 2 * gBaseStats[species].baseHP; stats[STAT_HP] = (((n + ivs + evs[STAT_HP] / 4) * level) / 100) + level + 10; } CALC_STAT(baseAttack, STAT_ATK); CALC_STAT(baseDefense, STAT_DEF); CALC_STAT(baseSpeed, STAT_SPEED); CALC_STAT(baseSpAttack, STAT_SPATK); CALC_STAT(baseSpDefense, STAT_SPDEF); } static void SwapDomeTrainers(int id1, int id2, u16 *statsArray) { int i; u16 temp; SWAP(statsArray[id1], statsArray[id2], temp); SWAP(DOME_TRAINERS[id1].trainerId, DOME_TRAINERS[id2].trainerId, temp); for (i = 0; i < FRONTIER_PARTY_SIZE; i++) SWAP(DOME_MONS[id1][i], DOME_MONS[id2][i], temp); } static void BufferDomeRoundText(void) { StringCopy(gStringVar1, gRoundsStringTable[gSaveBlock2Ptr->frontier.curChallengeBattleNum]); } static void BufferDomeOpponentName(void) { StringCopy(gStringVar1, gRoundsStringTable[gSaveBlock2Ptr->frontier.curChallengeBattleNum]); CopyDomeTrainerName(gStringVar2, gTrainerBattleOpponent_A); } static void InitDomeOpponentParty(void) { gPlayerPartyLostHP = 0; sPlayerPartyMaxHP = GetMonData(&gPlayerParty[0], MON_DATA_MAX_HP, NULL); sPlayerPartyMaxHP += GetMonData(&gPlayerParty[1], MON_DATA_MAX_HP, NULL); CalculatePlayerPartyCount(); CreateDomeOpponentMons(TrainerIdToTournamentId(gTrainerBattleOpponent_A)); } static void CreateDomeOpponentMon(u8 monPartyId, u16 tournamentTrainerId, u8 tournamentMonId, u32 otId) { int i; u8 friendship = MAX_FRIENDSHIP; #ifdef BUGFIX u8 fixedIv = GetDomeTrainerMonIvs(DOME_TRAINERS[tournamentTrainerId].trainerId); #else u8 fixedIv = GetDomeTrainerMonIvs(tournamentTrainerId); // BUG: Using the wrong ID. As a result, all Pokemon have ivs of 3. #endif u8 level = SetFacilityPtrsGetLevel(); CreateMonWithEVSpreadNatureOTID(&gEnemyParty[monPartyId], gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].species, level, gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].nature, fixedIv, gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].evSpread, otId); friendship = MAX_FRIENDSHIP; for (i = 0; i < MAX_MON_MOVES; i++) { SetMonMoveSlot(&gEnemyParty[monPartyId], gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].moves[i], i); if (gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].moves[i] == MOVE_FRUSTRATION) friendship = 0; } SetMonData(&gEnemyParty[monPartyId], MON_DATA_FRIENDSHIP, &friendship); SetMonData(&gEnemyParty[monPartyId], MON_DATA_HELD_ITEM, &gBattleFrontierHeldItems[gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].itemTableId]); } static void CreateDomeOpponentMons(u16 tournamentTrainerId) { u8 monsCount = 0; u32 otId = 0; int i, selectedMonBits; ZeroEnemyPartyMons(); selectedMonBits = GetDomeTrainerSelectedMons(tournamentTrainerId); otId = Random32(); if (Random() % 10 > 5) { // Create mon if it was selected, starting from front for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { if (selectedMonBits & 1) { CreateDomeOpponentMon(monsCount, tournamentTrainerId, i, otId); monsCount++; } selectedMonBits >>= 1; } } else { // Create mon if it was selected, starting from back for (i = FRONTIER_PARTY_SIZE - 1; i >= 0; i--) { if (selectedMonBits & (1 << (FRONTIER_PARTY_SIZE - 1))) { CreateDomeOpponentMon(monsCount, tournamentTrainerId, i, otId); monsCount++; } selectedMonBits <<= 1; } } } int GetDomeTrainerSelectedMons(u16 tournamentTrainerId) { int selectedMonBits; if (Random() & 1) { selectedMonBits = SelectOpponentMonsUsingPersonality(tournamentTrainerId, FALSE); if (selectedMonBits == 0) selectedMonBits = SelectOpponentMonsUsingOtId(tournamentTrainerId, TRUE); } else { selectedMonBits = SelectOpponentMonsUsingOtId(tournamentTrainerId, FALSE); if (selectedMonBits == 0) selectedMonBits = SelectOpponentMonsUsingPersonality(tournamentTrainerId, TRUE); } return selectedMonBits; } // Could probably use a better name once GetTypeEffectivenessPoints is clarified // Personality seems to be used to select a different weighting system for type effectiveness points static int SelectOpponentMonsUsingPersonality(u16 tournamentTrainerId, bool8 allowRandom) { int i, moveId, playerMonId; int partyMovePoints[FRONTIER_PARTY_SIZE]; for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { partyMovePoints[i] = 0; for (moveId = 0; moveId < MAX_MON_MOVES; moveId++) { for (playerMonId = 0; playerMonId < FRONTIER_PARTY_SIZE; playerMonId++) { if (DOME_TRAINERS[tournamentTrainerId].trainerId == TRAINER_FRONTIER_BRAIN) { partyMovePoints[i] += GetTypeEffectivenessPoints(GetFrontierBrainMonMove(i, moveId), GetMonData(&gPlayerParty[playerMonId], MON_DATA_SPECIES, NULL), MON_DATA_PERSONALITY); } else { partyMovePoints[i] += GetTypeEffectivenessPoints(gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][i]].moves[moveId], GetMonData(&gPlayerParty[playerMonId], MON_DATA_SPECIES, NULL), MON_DATA_PERSONALITY); } } } } return SelectOpponentMonsFromParty(partyMovePoints, allowRandom); } // See above function, identical but uses MON_DATA_OT_ID static int SelectOpponentMonsUsingOtId(u16 tournamentTrainerId, bool8 allowRandom) { int i, moveId, playerMonId; int partyMovePoints[FRONTIER_PARTY_SIZE]; for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { partyMovePoints[i] = 0; for (moveId = 0; moveId < MAX_MON_MOVES; moveId++) { for (playerMonId = 0; playerMonId < FRONTIER_PARTY_SIZE; playerMonId++) { if (DOME_TRAINERS[tournamentTrainerId].trainerId == TRAINER_FRONTIER_BRAIN) { partyMovePoints[i] += GetTypeEffectivenessPoints(GetFrontierBrainMonMove(i, moveId), GetMonData(&gPlayerParty[playerMonId], MON_DATA_SPECIES, NULL), MON_DATA_OT_ID); } else { partyMovePoints[i] += GetTypeEffectivenessPoints(gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][i]].moves[moveId], GetMonData(&gPlayerParty[playerMonId], MON_DATA_SPECIES, NULL), MON_DATA_OT_ID); } } } } return SelectOpponentMonsFromParty(partyMovePoints, allowRandom); } static int SelectOpponentMonsFromParty(int *partyMovePoints, bool8 allowRandom) { int i, j; int selectedMonBits = 0; int partyPositions[FRONTIER_PARTY_SIZE]; for (i = 0; i < FRONTIER_PARTY_SIZE; i++) partyPositions[i] = i; // All party mons have equal move score totals, choose randomly if (partyMovePoints[0] == partyMovePoints[1] && partyMovePoints[0] == partyMovePoints[2]) { if (allowRandom) { i = 0; while (i != DOME_BATTLE_PARTY_SIZE) { u32 rand = Random() & FRONTIER_PARTY_SIZE; if (rand != FRONTIER_PARTY_SIZE && !(selectedMonBits & gBitTable[rand])) { selectedMonBits |= gBitTable[rand]; i++; } } } } else { for (i = 0; i < DOME_BATTLE_PARTY_SIZE; i++) { for (j = i + 1; j < FRONTIER_PARTY_SIZE; j++) { int temp; if (partyMovePoints[i] < partyMovePoints[j]) { SWAP(partyMovePoints[i], partyMovePoints[j],temp) SWAP(partyPositions[i], partyPositions[j], temp) } if (partyMovePoints[i] == partyMovePoints[j] && (Random() & 1)) { SWAP(partyMovePoints[i], partyMovePoints[j],temp) SWAP(partyPositions[i], partyPositions[j], temp) } } } for (i = 0; i < DOME_BATTLE_PARTY_SIZE; i++) { selectedMonBits |= gBitTable[partyPositions[i]]; } } return selectedMonBits; } #define TYPE_x0 0 #define TYPE_x0_25 5 #define TYPE_x0_50 10 #define TYPE_x1 20 #define TYPE_x2 40 #define TYPE_x4 80 static int GetTypeEffectivenessPoints(int move, int targetSpecies, int arg2) { int defType1, defType2, defAbility, moveType; int i = 0; int typePower = TYPE_x1; if (move == MOVE_NONE || move == 0xFFFF || gBattleMoves[move].power == 0) return 0; defType1 = gBaseStats[targetSpecies].type1; defType2 = gBaseStats[targetSpecies].type2; defAbility = gBaseStats[targetSpecies].abilities[0]; moveType = gBattleMoves[move].type; if (defAbility == ABILITY_LEVITATE && moveType == TYPE_GROUND) { if (arg2 == 1) typePower = 8; } else { while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) { if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) { i += 3; continue; } if (TYPE_EFFECT_ATK_TYPE(i) == moveType) { // BUG: the value of TYPE_x2 does not exist in gTypeEffectiveness, so if defAbility is ABILITY_WONDER_GUARD, the conditional always fails #ifndef BUGFIX if (TYPE_EFFECT_DEF_TYPE(i) == defType1) if ((defAbility == ABILITY_WONDER_GUARD && TYPE_EFFECT_MULTIPLIER(i) == TYPE_x2) || defAbility != ABILITY_WONDER_GUARD) typePower = (typePower * TYPE_EFFECT_MULTIPLIER(i)) / 10; if (TYPE_EFFECT_DEF_TYPE(i) == defType2 && defType1 != defType2) if ((defAbility == ABILITY_WONDER_GUARD && TYPE_EFFECT_MULTIPLIER(i) == TYPE_x2) || defAbility != ABILITY_WONDER_GUARD) typePower = (typePower * TYPE_EFFECT_MULTIPLIER(i)) / 10; #else if (TYPE_EFFECT_DEF_TYPE(i) == defType1) if ((defAbility == ABILITY_WONDER_GUARD && TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_SUPER_EFFECTIVE) || defAbility != ABILITY_WONDER_GUARD) typePower = (typePower * TYPE_EFFECT_MULTIPLIER(i)) / 10; if (TYPE_EFFECT_DEF_TYPE(i) == defType2 && defType1 != defType2) if ((defAbility == ABILITY_WONDER_GUARD && TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_SUPER_EFFECTIVE) || defAbility != ABILITY_WONDER_GUARD) typePower = (typePower * TYPE_EFFECT_MULTIPLIER(i)) / 10; #endif } i += 3; } } switch (arg2) { case 0: switch (typePower) { case TYPE_x0_50: case TYPE_x0_25: case TYPE_x0: default: typePower = 0; break; case TYPE_x1: typePower = 2; break; case TYPE_x2: typePower = 4; break; case TYPE_x4: typePower = 8; break; } break; case 1: switch (typePower) { default: case TYPE_x1: typePower = 0; break; case TYPE_x0_25: typePower = 4; break; case TYPE_x0: typePower = 8; break; case TYPE_x0_50: typePower = 2; break; case TYPE_x2: typePower = -2; break; case TYPE_x4: typePower = -4; break; } break; case 2: switch (typePower) { case TYPE_x0: typePower = -16; break; case TYPE_x0_25: typePower = -8; break; case TYPE_x0_50: default: typePower = 0; break; case TYPE_x1: typePower = 4; break; case TYPE_x2: typePower = 12; break; case TYPE_x4: typePower = 20; break; } break; } return typePower; } // Duplicate of GetFrontierTrainerFixedIvs // NOTE: In CreateDomeOpponentMon a tournament trainer ID (0-15) is passed instead, resulting in all IVs of 3 // To fix, see CreateDomeOpponentMon static u8 GetDomeTrainerMonIvs(u16 trainerId) { u8 fixedIv; if (trainerId <= FRONTIER_TRAINER_JILL) // 0 - 99 fixedIv = 3; else if (trainerId <= FRONTIER_TRAINER_CHLOE) // 100 - 119 fixedIv = 6; else if (trainerId <= FRONTIER_TRAINER_SOFIA) // 120 - 139 fixedIv = 9; else if (trainerId <= FRONTIER_TRAINER_JAZLYN) // 140 - 159 fixedIv = 12; else if (trainerId <= FRONTIER_TRAINER_ALISON) // 160 - 179 fixedIv = 15; else if (trainerId <= FRONTIER_TRAINER_LAMAR) // 180 - 199 fixedIv = 18; else if (trainerId <= FRONTIER_TRAINER_TESS) // 200 - 219 fixedIv = 21; else // 220+ (- 299) fixedIv = MAX_PER_STAT_IVS; return fixedIv; } static int TournamentIdOfOpponent(int roundId, int trainerId) { int i, j, opponentMax; // Get trainer's tournament id for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { if (DOME_TRAINERS[i].trainerId == trainerId) break; } // Get trainer's opponent's tournament id if (roundId != DOME_ROUND1) { if (roundId == DOME_FINAL) opponentMax = sIdToOpponentId[i][roundId] + 8; else opponentMax = sIdToOpponentId[i][roundId] + 4; // Get first non-eliminated trainer in range of possible opponents for (j = sIdToOpponentId[i][roundId]; j < opponentMax; j++) { if (sTourneyTreeTrainerOpponentIds[j] != i && !DOME_TRAINERS[sTourneyTreeTrainerOpponentIds[j]].isEliminated) break; } if (j != opponentMax) return sTourneyTreeTrainerOpponentIds[j]; else return 0xFF; // Already eliminated } else { if (!DOME_TRAINERS[sIdToOpponentId[i][roundId]].isEliminated) return sIdToOpponentId[i][roundId]; else return 0xFF; // Already eliminated } } static void SetDomeOpponentId(void) { gTrainerBattleOpponent_A = TrainerIdOfPlayerOpponent(); } // While not an issue in-game, this will overflow if called after the player's opponent for the current round has been eliminated static u16 TrainerIdOfPlayerOpponent(void) { return DOME_TRAINERS[TournamentIdOfOpponent(gSaveBlock2Ptr->frontier.curChallengeBattleNum, TRAINER_PLAYER)].trainerId; } static void SetDomeOpponentGraphicsId(void) { SetBattleFacilityTrainerGfxId(gTrainerBattleOpponent_A, 0); } static void SaveDomeChallenge(void) { gSaveBlock2Ptr->frontier.challengeStatus = gSpecialVar_0x8005; VarSet(VAR_TEMP_0, 0); gSaveBlock2Ptr->frontier.challengePaused = TRUE; SaveGameFrontier(); } static void IncrementDomeStreaks(void) { u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode; u8 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE); if (gSaveBlock2Ptr->frontier.domeWinStreaks[battleMode][lvlMode] < 999) gSaveBlock2Ptr->frontier.domeWinStreaks[battleMode][lvlMode]++; if (gSaveBlock2Ptr->frontier.domeTotalChampionships[battleMode][lvlMode] < 999) gSaveBlock2Ptr->frontier.domeTotalChampionships[battleMode][lvlMode]++; if (gSaveBlock2Ptr->frontier.domeWinStreaks[battleMode][lvlMode] > gSaveBlock2Ptr->frontier.domeRecordWinStreaks[battleMode][lvlMode]) gSaveBlock2Ptr->frontier.domeRecordWinStreaks[battleMode][lvlMode] = gSaveBlock2Ptr->frontier.domeWinStreaks[battleMode][lvlMode]; } // For showing the opponent info card of the upcoming trainer static void ShowDomeOpponentInfo(void) { u8 taskId = CreateTask(Task_ShowTourneyInfoCard, 0); gTasks[taskId].tState = 0; gTasks[taskId].tTournamentId = TrainerIdToTournamentId(TrainerIdOfPlayerOpponent()); gTasks[taskId].tMode = INFOCARD_NEXT_OPPONENT; gTasks[taskId].tPrevTaskId = 0; SetMainCallback2(CB2_TourneyTree); } // For showing the opponent info card or the match info card static void Task_ShowTourneyInfoCard(u8 taskId) { int i; int tournamentId = gTasks[taskId].tTournamentId; int mode = gTasks[taskId].tMode; int id = gTasks[taskId].tPrevTaskId; switch (gTasks[taskId].tState) { case 0: SetHBlankCallback(NULL); SetVBlankCallback(NULL); EnableInterrupts(INTR_FLAG_VBLANK); CpuFill32(0, (void *)VRAM, VRAM_SIZE); ResetBgsAndClearDma3BusyFlags(0); InitBgsFromTemplates(0, sInfoCardBgTemplates, ARRAY_COUNT(sInfoCardBgTemplates)); InitWindows(sInfoCardWindowTemplates); DeactivateAllTextPrinters(); gBattle_BG0_X = 0; gBattle_BG0_Y = 0; gBattle_BG1_X = 0; gBattle_BG1_Y = 0; gBattle_BG3_X = 0; gBattle_BG3_Y = 0; if (mode == INFOCARD_MATCH) gBattle_BG2_X = 0, gBattle_BG2_Y = 0; else gBattle_BG2_X = 0, gBattle_BG2_Y = DISPLAY_HEIGHT; gTasks[taskId].tState++; break; case 1: SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); SetGpuReg(REG_OFFSET_BLDY, 0); SetGpuReg(REG_OFFSET_MOSAIC, 0); SetGpuReg(REG_OFFSET_WIN0H, 0); SetGpuReg(REG_OFFSET_WIN0V, 0); SetGpuReg(REG_OFFSET_WIN1H, 0); SetGpuReg(REG_OFFSET_WIN1V, 0); SetGpuReg(REG_OFFSET_WININ, 0); SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR); ResetPaletteFade(); ResetSpriteData(); FreeAllSpritePalettes(); gReservedSpritePaletteCount = 4; gTasks[taskId].tState++; break; case 2: DecompressAndLoadBgGfxUsingHeap(2, gDomeTourneyInfoCard_Gfx, 0x2000, 0, 0); DecompressAndLoadBgGfxUsingHeap(2, gDomeTourneyInfoCard_Tilemap, 0x2000, 0, 1); DecompressAndLoadBgGfxUsingHeap(3, gDomeTourneyInfoCardBg_Tilemap, 0x800, 0, 1); LoadCompressedSpriteSheet(sTourneyTreeButtonsSpriteSheet); LoadCompressedPalette(gDomeTourneyTree_Pal, 0, 0x200); LoadCompressedPalette(gDomeTourneyTreeButtons_Pal, 0x100, 0x200); LoadCompressedPalette(gBattleWindowTextPalette, 0xF0, 0x20); if (mode == INFOCARD_MATCH) LoadCompressedPalette(gDomeTourneyMatchCardBg_Pal, 0x50, 0x20); // Changes the moving info card bg to orange when in match card mode CpuFill32(0, gPlttBufferFaded, 0x400); ShowBg(0); ShowBg(1); ShowBg(2); ShowBg(3); gTasks[taskId].tState++; break; case 3: SetVBlankCallback(VblankCb_TourneyInfoCard); sInfoCard = AllocZeroed(sizeof(*sInfoCard)); for (i = 0; i < NUM_INFOCARD_SPRITES; i++) sInfoCard->spriteIds[i] = SPRITE_NONE; LoadMonIconPalettes(); i = CreateTask(Task_HandleInfoCardInput, 0); gTasks[i].data[0] = 0; gTasks[i].data[2] = 0; gTasks[i].data[3] = mode; gTasks[i].data[4] = id; if (mode == INFOCARD_MATCH) { DisplayMatchInfoOnCard(0, tournamentId); sInfoCard->pos = 1; } else { DisplayTrainerInfoOnCard(0, tournamentId); } SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_BG_ALL_ON | DISPCNT_OBJ_1D_MAP); if (mode != INFOCARD_NEXT_OPPONENT) { // Scroll up arrow id = CreateSprite(&sVerticalScrollArrowSpriteTemplate, 120, 4, 0); StartSpriteAnim(&gSprites[id], 0); gSprites[id].data[0] = i; // Scroll down arrow id = CreateSprite(&sVerticalScrollArrowSpriteTemplate, 120, 156, 0); StartSpriteAnim(&gSprites[id], 1); gSprites[id].data[0] = i; // Scroll left arrow id = CreateSprite(&sHorizontalScrollArrowSpriteTemplate, 6, 80, 0); StartSpriteAnim(&gSprites[id], 0); gSprites[id].data[0] = i; gSprites[id].data[1] = 0; if (mode == INFOCARD_TRAINER) gSprites[id].invisible = TRUE; // Scroll right arrow id = CreateSprite(&sHorizontalScrollArrowSpriteTemplate, 234, 80, 0); StartSpriteAnim(&gSprites[id], 1); gSprites[id].data[0] = i; gSprites[id].data[1] = 1; } DestroyTask(taskId); break; } } // Note: Card scrolling up means the current card goes down and another one appears from top. // The same is true for scrolling left. // That means that the sprite needs to move with the moving card in the opposite scrolling direction. static void SpriteCb_TrainerIconCardScrollUp(struct Sprite *sprite) { sprite->y += 4; if (sprite->data[0] != 0) { if (sprite->y >= -32) sprite->invisible = FALSE; if (++sprite->data[1] == 40) sprite->callback = SpriteCallbackDummy; } else { if (sprite->y >= 192) { sInfoCard->spriteIds[sprite->data[2]] = SPRITE_NONE; FreeAndDestroyTrainerPicSprite(sprite->data[3]); } } } static void SpriteCb_TrainerIconCardScrollDown(struct Sprite *sprite) { sprite->y -= 4; if (sprite->data[0] != 0) { if (sprite->y <= 192) sprite->invisible = FALSE; if (++sprite->data[1] == 40) sprite->callback = SpriteCallbackDummy; } else { if (sprite->y <= -32) { sInfoCard->spriteIds[sprite->data[2]] = SPRITE_NONE; FreeAndDestroyTrainerPicSprite(sprite->data[3]); } } } static void SpriteCb_TrainerIconCardScrollLeft(struct Sprite *sprite) { sprite->x += 4; if (sprite->data[0] != 0) { if (sprite->x >= -32) sprite->invisible = FALSE; if (++sprite->data[1] == 64) sprite->callback = SpriteCallbackDummy; } else { if (sprite->x >= DISPLAY_WIDTH + 32) { sInfoCard->spriteIds[sprite->data[2]] = SPRITE_NONE; FreeAndDestroyTrainerPicSprite(sprite->data[3]); } } } static void SpriteCb_TrainerIconCardScrollRight(struct Sprite *sprite) { sprite->x -= 4; if (sprite->data[0] != 0) { if (sprite->x <= DISPLAY_WIDTH + 32) sprite->invisible = FALSE; if (++sprite->data[1] == 64) sprite->callback = SpriteCallbackDummy; } else { if (sprite->x <= -32) { sInfoCard->spriteIds[sprite->data[2]] = SPRITE_NONE; FreeAndDestroyTrainerPicSprite(sprite->data[3]); } } } #define sMonIconStill data[3] static void SpriteCb_MonIcon(struct Sprite *sprite) { if (!sprite->sMonIconStill) UpdateMonIconFrame(sprite); } static void SpriteCb_MonIconCardScrollUp(struct Sprite *sprite) { if (!sprite->sMonIconStill) UpdateMonIconFrame(sprite); sprite->y += 4; if (sprite->data[0] != 0) { if (sprite->y >= -16) sprite->invisible = FALSE; if (++sprite->data[1] == 40) sprite->callback = SpriteCb_MonIcon; } else { if (sprite->y >= 176) { sInfoCard->spriteIds[sprite->data[2]] = SPRITE_NONE; FreeAndDestroyMonIconSprite(sprite); } } } static void SpriteCb_MonIconCardScrollDown(struct Sprite *sprite) { if (!sprite->sMonIconStill) UpdateMonIconFrame(sprite); sprite->y -= 4; if (sprite->data[0] != 0) { if (sprite->y <= 176) sprite->invisible = FALSE; if (++sprite->data[1] == 40) sprite->callback = SpriteCb_MonIcon; } else { if (sprite->y <= -16) { sInfoCard->spriteIds[sprite->data[2]] = SPRITE_NONE; FreeAndDestroyMonIconSprite(sprite); } } } static void SpriteCb_MonIconCardScrollLeft(struct Sprite *sprite) { if (!sprite->sMonIconStill) UpdateMonIconFrame(sprite); sprite->x += 4; if (sprite->data[0] != 0) { if (sprite->x >= -16) sprite->invisible = FALSE; if (++sprite->data[1] == 64) sprite->callback = SpriteCb_MonIcon; } else { if (sprite->x >= DISPLAY_WIDTH + 16) { sInfoCard->spriteIds[sprite->data[2]] = SPRITE_NONE; FreeAndDestroyMonIconSprite(sprite); } } } static void SpriteCb_MonIconCardScrollRight(struct Sprite *sprite) { if (!sprite->sMonIconStill) UpdateMonIconFrame(sprite); sprite->x -= 4; if (sprite->data[0] != 0) { if (sprite->x <= DISPLAY_WIDTH + 16) sprite->invisible = FALSE; if (++sprite->data[1] == 64) sprite->callback = SpriteCb_MonIcon; } else { if (sprite->x <= -16) { sInfoCard->spriteIds[sprite->data[2]] = SPRITE_NONE; FreeAndDestroyMonIconSprite(sprite); } } } static void SpriteCb_HorizontalScrollArrow(struct Sprite *sprite) { int taskId1 = sprite->data[0]; int arrId = gTasks[gTasks[taskId1].data[4]].data[1]; int tournmanetTrainerId = sTourneyTreeTrainerIds[arrId]; int roundId = gSaveBlock2Ptr->frontier.curChallengeBattleNum; if (gTasks[taskId1].data[3] == 1) { if (sprite->data[1]) { if ((DOME_TRAINERS[tournmanetTrainerId].isEliminated && sInfoCard->pos - 1 < DOME_TRAINERS[tournmanetTrainerId].eliminatedAt)) { sprite->invisible = FALSE; } else if (!DOME_TRAINERS[tournmanetTrainerId].isEliminated && sInfoCard->pos - 1 < roundId) { sprite->invisible = FALSE; } else { if (gTasks[taskId1].data[0] == 2) sprite->invisible = TRUE; } } else { if (sInfoCard->pos != 0) { sprite->invisible = FALSE; } else { if (gTasks[taskId1].data[0] == 2) sprite->invisible = TRUE; } } } else { if (sprite->data[1]) { if (sInfoCard->pos > 1) { if (gTasks[taskId1].data[0] == 2) sprite->invisible = TRUE; } else { sprite->invisible = FALSE; } } else { if (sInfoCard->pos != 0) { sprite->invisible = FALSE; } else { if (gTasks[taskId1].data[0] == 2) sprite->invisible = TRUE; } } } } static void SpriteCb_VerticalScrollArrow(struct Sprite *sprite) { int taskId1 = sprite->data[0]; if (gTasks[taskId1].data[3] == 1) { if (sInfoCard->pos != 0) { if (gTasks[taskId1].data[0] == 2) sprite->invisible = TRUE; } else { sprite->invisible = FALSE; } } else { if (sInfoCard->pos != 1) { if (gTasks[taskId1].data[0] == 2) sprite->invisible = TRUE; } else { sprite->invisible = FALSE; } } } // Task states for Task_HandleInfoCardInput #define STATE_FADE_IN 0 #define STATE_WAIT_FADE 1 #define STATE_GET_INPUT 2 #define STATE_REACT_INPUT 3 #define STATE_MOVE_UP 4 #define STATE_MOVE_DOWN 5 #define STATE_MOVE_LEFT 6 #define STATE_MOVE_RIGHT 7 #define STATE_CLOSE_CARD 8 #define tUsingAlternateSlot data[2] // CARD_ALTERNATE_SLOT static void Task_HandleInfoCardInput(u8 taskId) { int i; int windowId = 0; int mode = gTasks[taskId].data[3]; int taskId2 = gTasks[taskId].data[4]; int trainerTourneyId = 0; int matchNo = 0; switch (gTasks[taskId].tState) { case STATE_FADE_IN: if (!gPaletteFade.active) { BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK); gTasks[taskId].tState = STATE_WAIT_FADE; } break; case STATE_WAIT_FADE: if (!gPaletteFade.active) gTasks[taskId].tState = STATE_GET_INPUT; break; case STATE_GET_INPUT: i = Task_GetInfoCardInput(taskId); switch (i) { case INFOCARD_INPUT_AB: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); gTasks[taskId].tState = STATE_CLOSE_CARD; break; case TRAINERCARD_INPUT_UP ... TRAINERCARD_INPUT_RIGHT: case MATCHCARD_INPUT_UP ... MATCHCARD_INPUT_RIGHT: gTasks[taskId].data[5] = i; if (gTasks[taskId].tUsingAlternateSlot) windowId = 9; else windowId = 0; for (i = windowId; i < windowId + 9; i++) { CopyWindowToVram(i, COPYWIN_GFX); FillWindowPixelBuffer(i, PIXEL_FILL(0)); } gTasks[taskId].tState = STATE_REACT_INPUT; break; case INFOCARD_INPUT_NONE: break; } break; case STATE_REACT_INPUT: i = gTasks[taskId].data[5]; switch (i) { case TRAINERCARD_INPUT_UP: case MATCHCARD_INPUT_UP: if (gTasks[taskId].tUsingAlternateSlot) { gBattle_BG0_X = 0; gBattle_BG0_Y = 0; gBattle_BG1_X = 0; gBattle_BG1_Y = DISPLAY_HEIGHT; } else { gBattle_BG0_X = 0; gBattle_BG0_Y = DISPLAY_HEIGHT; gBattle_BG1_X = 0; gBattle_BG1_Y = 0; } if (i == TRAINERCARD_INPUT_UP) { if (sInfoCard->pos == 0) { gBattle_BG2_X = 0; gBattle_BG2_Y = DISPLAY_HEIGHT * 2; trainerTourneyId = sTourneyTreeTrainerIds[gTasks[taskId2].data[1]]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_UP, trainerTourneyId); } else { gBattle_BG2_X = DISPLAY_WIDTH + 16; gBattle_BG2_Y = 0; trainerTourneyId = sTourneyTreeTrainerIds[gTasks[taskId2].data[1]]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_UP, trainerTourneyId); sInfoCard->pos = 0; } } else // i == MATCHCARD_INPUT_UP { if (sInfoCard->pos == 0) { matchNo = gTasks[taskId2].data[1] - 16; BufferDomeWinString(matchNo, sInfoCard->tournamentIds); gBattle_BG2_X = 0; gBattle_BG2_Y = DISPLAY_HEIGHT * 2; trainerTourneyId = sInfoCard->tournamentIds[0]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_UP, trainerTourneyId); } else if (sInfoCard->pos == 2) { matchNo = gTasks[taskId2].data[1] - 16; BufferDomeWinString(matchNo, sInfoCard->tournamentIds); gBattle_BG2_X = 0; gBattle_BG2_Y = DISPLAY_HEIGHT * 2; trainerTourneyId = sInfoCard->tournamentIds[1]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_UP, trainerTourneyId); } else { gBattle_BG2_X = DISPLAY_WIDTH + 16; gBattle_BG2_Y = DISPLAY_HEIGHT; matchNo = gTasks[taskId2].data[1] - 16; DisplayMatchInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_UP, matchNo); } } for (i = 0; i < NUM_INFOCARD_SPRITES / 2; i++) { if (i < 2) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollUp; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollUp; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } for (i = NUM_INFOCARD_SPRITES / 2; i < NUM_INFOCARD_SPRITES; i++) { if (i < 10) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollUp; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollUp; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } gTasks[taskId].tState = STATE_MOVE_UP; gTasks[taskId].data[5] = 0; break; case TRAINERCARD_INPUT_DOWN: case MATCHCARD_INPUT_DOWN: if (gTasks[taskId].tUsingAlternateSlot) { gBattle_BG0_X = 0; gBattle_BG0_Y = 0; gBattle_BG1_X = 0; gBattle_BG1_Y = -DISPLAY_HEIGHT; } else { gBattle_BG0_X = 0; gBattle_BG0_Y = -DISPLAY_HEIGHT; gBattle_BG1_X = 0; gBattle_BG1_Y = 0; } if (i == TRAINERCARD_INPUT_DOWN) { if (sInfoCard->pos == 0) { gBattle_BG2_X = 0; gBattle_BG2_Y = DISPLAY_HEIGHT; trainerTourneyId = sTourneyTreeTrainerIds[gTasks[taskId2].data[1]]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_DOWN, trainerTourneyId); } else { gBattle_BG2_X = 0; gBattle_BG2_Y = 0; trainerTourneyId = sTourneyTreeTrainerIds[gTasks[taskId2].data[1]]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_DOWN, trainerTourneyId); sInfoCard->pos = 0; } } else // i == MATCHCARD_INPUT_DOWN { if (sInfoCard->pos == 0) { matchNo = gTasks[taskId2].data[1] - 16; BufferDomeWinString(matchNo, sInfoCard->tournamentIds); gBattle_BG2_X = 0; gBattle_BG2_Y = DISPLAY_HEIGHT; trainerTourneyId = sInfoCard->tournamentIds[0]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_DOWN, trainerTourneyId); } else if (sInfoCard->pos == 2) { matchNo = gTasks[taskId2].data[1] - 16; BufferDomeWinString(matchNo, sInfoCard->tournamentIds); gBattle_BG2_X = 0; gBattle_BG2_Y = DISPLAY_HEIGHT; trainerTourneyId = sInfoCard->tournamentIds[1]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_DOWN, trainerTourneyId); } else { gBattle_BG2_X = DISPLAY_WIDTH + 16; gBattle_BG2_Y = 0; matchNo = gTasks[taskId2].data[1] - 16; DisplayMatchInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_DOWN, matchNo); } } for (i = 0; i < NUM_INFOCARD_SPRITES / 2; i++) { if (i < 2) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollDown; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollDown; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } for (i = NUM_INFOCARD_SPRITES / 2; i < NUM_INFOCARD_SPRITES; i++) { if (i < 10) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollDown; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollDown; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } gTasks[taskId].tState = STATE_MOVE_DOWN; gTasks[taskId].data[5] = 0; break; case TRAINERCARD_INPUT_LEFT: if (gTasks[taskId].tUsingAlternateSlot) { gBattle_BG0_X = 0; gBattle_BG0_Y = 0; gBattle_BG1_X = DISPLAY_WIDTH + 16; gBattle_BG1_Y = 0; } else { gBattle_BG0_X = DISPLAY_WIDTH + 16; gBattle_BG0_Y = 0; gBattle_BG1_X = 0; gBattle_BG1_Y = 0; } if (sInfoCard->pos == 0) { gBattle_BG2_X = DISPLAY_WIDTH + 16; gBattle_BG2_Y = DISPLAY_HEIGHT; trainerTourneyId = sTourneyTreeTrainerIds[gTasks[taskId2].data[1]]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_LEFT, trainerTourneyId); } else { gBattle_BG2_X = DISPLAY_WIDTH + 16; gBattle_BG2_Y = 0; matchNo = sIdToMatchNumber[gTasks[taskId2].data[1]][sInfoCard->pos - 1]; DisplayMatchInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_LEFT, matchNo); } for (i = 0; i < NUM_INFOCARD_SPRITES / 2; i++) { if (i < 2) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollLeft; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollLeft; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } for (i = NUM_INFOCARD_SPRITES / 2; i < NUM_INFOCARD_SPRITES; i++) { if (i < 10) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollLeft; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollLeft; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } gTasks[taskId].tState = STATE_MOVE_LEFT; gTasks[taskId].data[5] = 0; break; case MATCHCARD_INPUT_LEFT: if (gTasks[taskId].tUsingAlternateSlot) { gBattle_BG0_X = 0; gBattle_BG0_Y = 0; gBattle_BG1_X = DISPLAY_WIDTH + 16; gBattle_BG1_Y = 0; } else { gBattle_BG0_X = DISPLAY_WIDTH + 16; gBattle_BG0_Y = 0; gBattle_BG1_X = 0; gBattle_BG1_Y = 0; } if (sInfoCard->pos == 0) { gBattle_BG2_X = DISPLAY_WIDTH + 16; gBattle_BG2_Y = DISPLAY_HEIGHT; trainerTourneyId = sInfoCard->tournamentIds[0]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_LEFT, trainerTourneyId); } else { gBattle_BG2_X = 0; gBattle_BG2_Y = DISPLAY_HEIGHT; matchNo = gTasks[taskId2].data[1] - 16; DisplayMatchInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_LEFT, matchNo); } for (i = 0; i < NUM_INFOCARD_SPRITES / 2; i++) { if (i < 2) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollLeft; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollLeft; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } for (i = NUM_INFOCARD_SPRITES / 2; i < NUM_INFOCARD_SPRITES; i++) { if (i < 10) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollLeft; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollLeft; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } gTasks[taskId].tState = STATE_MOVE_LEFT; gTasks[taskId].data[5] = 0; break; case TRAINERCARD_INPUT_RIGHT: if (gTasks[taskId].tUsingAlternateSlot) { gBattle_BG0_X = 0; gBattle_BG0_Y = 0; gBattle_BG1_X = -(DISPLAY_WIDTH + 16); gBattle_BG1_Y = 0; } else { gBattle_BG0_X = -(DISPLAY_WIDTH + 16); gBattle_BG0_Y = 0; gBattle_BG1_X = 0; gBattle_BG1_Y = 0; } if (sInfoCard->pos == 1) { gBattle_BG2_X = 0; gBattle_BG2_Y = DISPLAY_HEIGHT; } else { gBattle_BG2_X = 0; gBattle_BG2_Y = 0; } matchNo = sIdToMatchNumber[gTasks[taskId2].data[1]][sInfoCard->pos - 1]; DisplayMatchInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_RIGHT, matchNo); for (i = 0; i < NUM_INFOCARD_SPRITES / 2; i++) { if (i < 2) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollRight; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollRight; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } for (i = NUM_INFOCARD_SPRITES / 2; i < NUM_INFOCARD_SPRITES; i++) { if (i < 10) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollRight; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollRight; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } gTasks[taskId].tState = STATE_MOVE_RIGHT; gTasks[taskId].data[5] = 0; break; case MATCHCARD_INPUT_RIGHT: if (gTasks[taskId].tUsingAlternateSlot) { gBattle_BG0_X = 0; gBattle_BG0_Y = 0; gBattle_BG1_X = -(DISPLAY_WIDTH + 16); gBattle_BG1_Y = 0; } else { gBattle_BG0_X = -(DISPLAY_WIDTH + 16); gBattle_BG0_Y = 0; gBattle_BG1_X = 0; gBattle_BG1_Y = 0; } if (sInfoCard->pos == 2) { gBattle_BG2_X = DISPLAY_WIDTH + 16; gBattle_BG2_Y = DISPLAY_HEIGHT; trainerTourneyId = sInfoCard->tournamentIds[1]; DisplayTrainerInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_RIGHT, trainerTourneyId); } else { gBattle_BG2_X = 0; gBattle_BG2_Y = DISPLAY_HEIGHT; matchNo = gTasks[taskId2].data[1] - 16; DisplayMatchInfoOnCard(gTasks[taskId].tUsingAlternateSlot | MOVE_CARD_RIGHT, matchNo); } for (i = 0; i < NUM_INFOCARD_SPRITES / 2; i++) { if (i < 2) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollRight; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollRight; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot ^ 1; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } for (i = NUM_INFOCARD_SPRITES / 2; i < NUM_INFOCARD_SPRITES; i++) { if (i < 10) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_TrainerIconCardScrollRight; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; gSprites[sInfoCard->spriteIds[i]].data[3] = sInfoCard->spriteIds[i]; } } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) { gSprites[sInfoCard->spriteIds[i]].callback = SpriteCb_MonIconCardScrollRight; gSprites[sInfoCard->spriteIds[i]].data[0] = gTasks[taskId].tUsingAlternateSlot; gSprites[sInfoCard->spriteIds[i]].data[1] = 0; gSprites[sInfoCard->spriteIds[i]].data[2] = i; } } } gTasks[taskId].tState = STATE_MOVE_RIGHT; gTasks[taskId].data[5] = 0; break; } break; case STATE_MOVE_UP: if (++gTasks[taskId].data[5] != 41) { gBattle_BG0_Y -= 4; gBattle_BG1_Y -= 4; gBattle_BG2_Y -= 4; } else { gTasks[taskId].tState = STATE_GET_INPUT; } break; case STATE_MOVE_DOWN: if (++gTasks[taskId].data[5] != 41) { gBattle_BG0_Y += 4; gBattle_BG1_Y += 4; gBattle_BG2_Y += 4; } else { gTasks[taskId].tState = STATE_GET_INPUT; } break; case STATE_MOVE_LEFT: if (++gTasks[taskId].data[5] != 65) { gBattle_BG0_X -= 4; gBattle_BG1_X -= 4; gBattle_BG2_X -= 4; } else { gTasks[taskId].tState = STATE_GET_INPUT; } break; case STATE_MOVE_RIGHT: if (++gTasks[taskId].data[5] != 65) { gBattle_BG0_X += 4; gBattle_BG1_X += 4; gBattle_BG2_X += 4; } else { gTasks[taskId].tState = STATE_GET_INPUT; } break; case STATE_CLOSE_CARD: if (!gPaletteFade.active) { for (i = 0; i < NUM_INFOCARD_SPRITES / 2; i++) { if (i < 2) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) FreeAndDestroyTrainerPicSprite(sInfoCard->spriteIds[i]); } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) FreeAndDestroyMonIconSprite(&gSprites[sInfoCard->spriteIds[i]]); } } for (i = NUM_INFOCARD_SPRITES / 2; i < NUM_INFOCARD_SPRITES; i++) { if (i < 10) { if (sInfoCard->spriteIds[i] != SPRITE_NONE) FreeAndDestroyTrainerPicSprite(sInfoCard->spriteIds[i]); } else { if (sInfoCard->spriteIds[i] != SPRITE_NONE) FreeAndDestroyMonIconSprite(&gSprites[sInfoCard->spriteIds[i]]); } } FreeMonIconPalettes(); FREE_AND_SET_NULL(sInfoCard); FreeAllWindowBuffers(); if (mode == INFOCARD_NEXT_OPPONENT) { SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); } else { i = CreateTask(Task_ShowTourneyTree, 0); gTasks[i].data[0] = 0; gTasks[i].tNotInteractive = FALSE; gTasks[i].data[2] = 3; gTasks[i].data[3] = gTasks[taskId].data[4]; gTasks[i].tIsPrevTourneyTree = gTasks[taskId2].data[6]; } DestroyTask(taskId); } break; } } // undefine task states for Task_HandleInfoCardInput #undef STATE_FADE_IN #undef STATE_WAIT_FADE #undef STATE_GET_INPUT #undef STATE_REACT_INPUT #undef STATE_MOVE_UP #undef STATE_MOVE_DOWN #undef STATE_MOVE_LEFT #undef STATE_MOVE_RIGHT #undef STATE_CLOSE_CARD static u8 Task_GetInfoCardInput(u8 taskId) { u8 input = INFOCARD_INPUT_NONE; int taskId2 = gTasks[taskId].data[4]; int position = gTasks[taskId2].data[1]; u8 tourneyId = sTourneyTreeTrainerIds[position]; u16 roundId = gSaveBlock2Ptr->frontier.curChallengeBattleNum; if (JOY_NEW(A_BUTTON | B_BUTTON)) input = INFOCARD_INPUT_AB; // Next opponent card cant scroll if (gTasks[taskId].data[3] == INFOCARD_NEXT_OPPONENT) return input; if (gTasks[taskId].data[3] == INFOCARD_TRAINER) { // For trainer info cards, pos is 0 when on a trainer info card (not viewing that trainer's match progression) // Scrolling up/down from a trainer info card goes to other trainer info cards if (JOY_NEW(DPAD_UP) && sInfoCard->pos == 0) { if (position == 0) position = DOME_TOURNAMENT_TRAINERS_COUNT - 1; else position--; input = TRAINERCARD_INPUT_UP; } else if (JOY_NEW(DPAD_DOWN) && sInfoCard->pos == 0) { if (position == DOME_TOURNAMENT_TRAINERS_COUNT - 1) position = 0; else position++; input = TRAINERCARD_INPUT_DOWN; } // Scrolling left can only be done after scrolling right else if (JOY_NEW(DPAD_LEFT) && sInfoCard->pos != 0) { sInfoCard->pos--; input = TRAINERCARD_INPUT_LEFT; } // Scrolling right from a trainer info card shows their match progression else if (JOY_NEW(DPAD_RIGHT)) { // Can only scroll right from a trainer card until the round they were eliminated if (DOME_TRAINERS[tourneyId].isEliminated && sInfoCard->pos - 1 < DOME_TRAINERS[tourneyId].eliminatedAt) { sInfoCard->pos++; input = TRAINERCARD_INPUT_RIGHT; } // otherwise can scroll as far right as the current round allows if (!DOME_TRAINERS[tourneyId].isEliminated && sInfoCard->pos - 1 < roundId) { sInfoCard->pos++; input = TRAINERCARD_INPUT_RIGHT; } } if (input == INFOCARD_INPUT_AB) { if (sInfoCard->pos != 0) gTasks[taskId2].data[1] = sTrainerAndRoundToLastMatchCardNum[position / 2][sInfoCard->pos - 1]; else gTasks[taskId2].data[1] = position; } } else // gTasks[taskId].data[3] == INFOCARD_MATCH { // For match info cards, pos is 1 when on the match card, 0 when on the left trainer, and 1 when on the right trainer // Scrolling up/down from a match info card goes to the next/previous match if (JOY_NEW(DPAD_UP) && sInfoCard->pos == 1) { if (position == DOME_TOURNAMENT_TRAINERS_COUNT) position = sLastMatchCardNum[roundId]; else position--; input = MATCHCARD_INPUT_UP; } else if (JOY_NEW(DPAD_DOWN) && sInfoCard->pos == 1) { if (position == sLastMatchCardNum[roundId]) position = DOME_TOURNAMENT_TRAINERS_COUNT; else position++; input = MATCHCARD_INPUT_DOWN; } // Scrolling left/right from a match info card shows the trainer info card of the competitors for that match else if (JOY_NEW(DPAD_LEFT) && sInfoCard->pos != 0) { input = MATCHCARD_INPUT_LEFT; sInfoCard->pos--; } else if (JOY_NEW(DPAD_RIGHT) && (sInfoCard->pos == 0 || sInfoCard->pos == 1)) { input = MATCHCARD_INPUT_RIGHT; sInfoCard->pos++; } if (input == INFOCARD_INPUT_AB) { if (sInfoCard->pos == 0) // On left trainer info card gTasks[taskId2].data[1] = sTournamentIdToPairedTrainerIds[sInfoCard->tournamentIds[0]]; else if (sInfoCard->pos == 2) // On right trainer info card gTasks[taskId2].data[1] = sTournamentIdToPairedTrainerIds[sInfoCard->tournamentIds[1]]; else // On match info card gTasks[taskId2].data[1] = position; } } if (input != INFOCARD_INPUT_NONE && input != INFOCARD_INPUT_AB) { PlaySE(SE_SELECT); gTasks[taskId2].data[1] = position; gTasks[taskId].tUsingAlternateSlot ^= 1; } return input; } #undef tUsingAlternateSlot // allocatedArray below needs to be large enough to hold stat totals for each mon, or totals of each type of move points #define ALLOC_ARRAY_SIZE (NUM_STATS * FRONTIER_PARTY_SIZE >= NUM_MOVE_POINT_TYPES ? (NUM_STATS * FRONTIER_PARTY_SIZE) : NUM_MOVE_POINT_TYPES) static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId) { struct TextPrinterTemplate textPrinter; int i, j, k; int trainerId = 0; u8 nature = 0; int arrId = 0; int windowId = 0; int x = 0, y = 0; u8 palSlot = 0; s16 *allocatedArray = AllocZeroed(sizeof(s16) * ALLOC_ARRAY_SIZE); trainerId = DOME_TRAINERS[trainerTourneyId].trainerId; if (flags & CARD_ALTERNATE_SLOT) arrId = 2 * (FRONTIER_PARTY_SIZE + 1), windowId = 9, palSlot = 2; if (flags & MOVE_CARD_RIGHT) x = DISPLAY_WIDTH + 16; if (flags & MOVE_CARD_DOWN) y = DISPLAY_HEIGHT; if (flags & MOVE_CARD_LEFT) x = -(DISPLAY_WIDTH + 16); if (flags & MOVE_CARD_UP) y = -DISPLAY_HEIGHT; // Create trainer pic sprite if (trainerId == TRAINER_PLAYER) sInfoCard->spriteIds[arrId] = CreateTrainerPicSprite(PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender), TRUE, x + 48, y + 64, palSlot + 12, TAG_NONE); else if (trainerId == TRAINER_FRONTIER_BRAIN) sInfoCard->spriteIds[arrId] = CreateTrainerPicSprite(GetDomeBrainTrainerPicId(), TRUE, x + 48, y + 64, palSlot + 12, TAG_NONE); else sInfoCard->spriteIds[arrId] = CreateTrainerPicSprite(GetFrontierTrainerFrontSpriteId(trainerId), TRUE, x + 48, y + 64, palSlot + 12, TAG_NONE); if (flags & MOVE_CARD) gSprites[sInfoCard->spriteIds[arrId]].invisible = TRUE; // Create party mon icons for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { if (trainerId == TRAINER_PLAYER) { sInfoCard->spriteIds[2 + i + arrId] = CreateMonIcon(DOME_MONS[trainerTourneyId][i], SpriteCb_MonIcon, x | sInfoTrainerMonX[i], y + sInfoTrainerMonY[i], 0, 0, TRUE); gSprites[sInfoCard->spriteIds[2 + i + arrId]].oam.priority = 0; } else if (trainerId == TRAINER_FRONTIER_BRAIN) { sInfoCard->spriteIds[2 + i + arrId] = CreateMonIcon(DOME_MONS[trainerTourneyId][i], SpriteCb_MonIcon, x | sInfoTrainerMonX[i], y + sInfoTrainerMonY[i], 0, 0, TRUE); gSprites[sInfoCard->spriteIds[2 + i + arrId]].oam.priority = 0; } else { sInfoCard->spriteIds[2 + i + arrId] = CreateMonIcon(gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].species, SpriteCb_MonIcon, x | sInfoTrainerMonX[i], y + sInfoTrainerMonY[i], 0, 0, TRUE); gSprites[sInfoCard->spriteIds[2 + i + arrId]].oam.priority = 0; } if (flags & MOVE_CARD) gSprites[sInfoCard->spriteIds[2 + i + arrId]].invisible = TRUE; } // Initialize the text printer textPrinter.fontId = FONT_SHORT; textPrinter.x = 0; textPrinter.y = 0; textPrinter.currentX = textPrinter.x; textPrinter.currentY = textPrinter.y; textPrinter.letterSpacing = 2; textPrinter.lineSpacing = 0; textPrinter.unk = 0; textPrinter.fgColor = TEXT_DYNAMIC_COLOR_5; textPrinter.bgColor = TEXT_COLOR_TRANSPARENT; textPrinter.shadowColor = TEXT_DYNAMIC_COLOR_4; // Get class and trainer name i = 0; if (trainerId == TRAINER_PLAYER) j = gFacilityClassToTrainerClass[FACILITY_CLASS_BRENDAN]; else if (trainerId == TRAINER_FRONTIER_BRAIN) j = GetDomeBrainTrainerClass(); else j = GetFrontierOpponentClass(trainerId); for (;gTrainerClassNames[j][i] != EOS; i++) gStringVar1[i] = gTrainerClassNames[j][i]; gStringVar1[i] = CHAR_SPACE; gStringVar1[i + 1] = EOS; if (trainerId == TRAINER_PLAYER) { StringAppend(gStringVar1, gSaveBlock2Ptr->playerName); } else if (trainerId == TRAINER_FRONTIER_BRAIN) { CopyDomeBrainTrainerName(gStringVar2); StringAppend(gStringVar1, gStringVar2); } else { CopyDomeTrainerName(gStringVar2, trainerId); StringAppend(gStringVar1, gStringVar2); } // Print class and trainer name textPrinter.currentX = GetStringCenterAlignXOffsetWithLetterSpacing(textPrinter.fontId, gStringVar1, 0xD0, textPrinter.letterSpacing); textPrinter.currentChar = gStringVar1; textPrinter.windowId = windowId; PutWindowTilemap(windowId); CopyWindowToVram(windowId, COPYWIN_FULL); AddTextPrinter(&textPrinter, 0, NULL); textPrinter.letterSpacing = 0; // Print names of the party mons for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { textPrinter.currentY = sSpeciesNameTextYCoords[i]; if (trainerId == TRAINER_PLAYER) textPrinter.currentChar = gSpeciesNames[DOME_MONS[trainerTourneyId][i]]; else if (trainerId == TRAINER_FRONTIER_BRAIN) textPrinter.currentChar = gSpeciesNames[DOME_MONS[trainerTourneyId][i]]; else textPrinter.currentChar = gSpeciesNames[gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].species]; textPrinter.windowId = 1 + i + windowId; if (i == 1) textPrinter.currentX = 7; else textPrinter.currentX = 0; PutWindowTilemap(1 + i + windowId); CopyWindowToVram(1 + i + windowId, COPYWIN_FULL); AddTextPrinter(&textPrinter, 0, NULL); } PutWindowTilemap(windowId + 4); CopyWindowToVram(windowId + 4, COPYWIN_FULL); // Print text about trainers potential in the tourney if (trainerId == TRAINER_FRONTIER_BRAIN) textPrinter.currentChar = sBattleDomePotentialTexts[DOME_TOURNAMENT_TRAINERS_COUNT]; else textPrinter.currentChar = sBattleDomePotentialTexts[trainerTourneyId]; textPrinter.fontId = FONT_NORMAL; textPrinter.windowId = windowId + 4; textPrinter.currentX = 0; textPrinter.y = 4; textPrinter.currentY = 4; AddTextPrinter(&textPrinter, 0, NULL); // Calculate move scores to determine the trainers battle style for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { for (j = 0; j < MAX_MON_MOVES; j++) { for (k = 0; k < NUM_MOVE_POINT_TYPES; k++) { if (trainerId == TRAINER_FRONTIER_BRAIN) allocatedArray[k] += sBattleStyleMovePoints[GetFrontierBrainMonMove(i, j)][k]; else if (trainerId == TRAINER_PLAYER) allocatedArray[k] += sBattleStyleMovePoints[gSaveBlock2Ptr->frontier.domePlayerPartyData[i].moves[j]][k]; else allocatedArray[k] += sBattleStyleMovePoints[gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].moves[j]][k]; } } } // Get the battle style the trainer uses // Each element of sBattleStyleThresholds is an array of point thresholds for particular move qualities // If all the point thresholds in the array are satisfied, the player is considered to be using that battle style for (i = 0; i < ARRAY_COUNT(sBattleStyleThresholds); i++) { int thresholdStatCount = 0; for (k = 0, j = 0; j < NUM_MOVE_POINT_TYPES; j++) { if (sBattleStyleThresholds[i][j] != 0) { thresholdStatCount++; if (allocatedArray[j] != 0 && allocatedArray[j] >= sBattleStyleThresholds[i][j]) k++; // number of point thresholds met/exceeded } } if (thresholdStatCount == k) break; // All thresholds for battle style met/exceeded, player uses this battle style } // Print the trainers battle style textPrinter.currentChar = sBattleDomeOpponentStyleTexts[i]; textPrinter.y = 20; textPrinter.currentY = 20; AddTextPrinter(&textPrinter, 0, NULL); for (i = 0; i < ALLOC_ARRAY_SIZE; i++) allocatedArray[i] = 0; // Calculate EV/nature points for the stat portion of battle style if (trainerId == TRAINER_FRONTIER_BRAIN || trainerId == TRAINER_PLAYER) { for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { // Add the EVs for this mon for (j = 0; j < NUM_STATS; j++) { if (trainerId == TRAINER_FRONTIER_BRAIN) allocatedArray[j] = GetFrontierBrainMonEvs(i, j); else allocatedArray[j] = gSaveBlock2Ptr->frontier.domePlayerPartyData[i].evs[j]; } // HP doesnt have a nature modifier, so just add it here allocatedArray[NUM_STATS] += allocatedArray[STAT_HP]; // Add the EVs with the nature modifier for this mon and and track number of negative natures for (j = 0; j < NUM_NATURE_STATS; j++) { if (trainerId == TRAINER_FRONTIER_BRAIN) nature = GetFrontierBrainMonNature(i); else nature = gSaveBlock2Ptr->frontier.domePlayerPartyData[i].nature; if (gNatureStatTable[nature][j] > 0) { allocatedArray[j + NUM_STATS + 1] += (allocatedArray[j + 1] * 110) / 100; } else if (gNatureStatTable[nature][j] < 0) { allocatedArray[j + NUM_STATS + 1] += (allocatedArray[j + 1] * 90) / 100; allocatedArray[j + NUM_STATS + NUM_NATURE_STATS + 2]++; } else { allocatedArray[j + NUM_STATS + 1] += allocatedArray[j + 1]; } } } for (j = 0, i = 0; i < NUM_STATS; i++) j += allocatedArray[NUM_STATS + i]; for (i = 0; i < NUM_STATS; i++) allocatedArray[i] = (allocatedArray[NUM_STATS + i] * 100) / j; } // Same as above but for regular trainers instead of the frontier brain or player else { for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { int evBits = gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].evSpread; for (k = 0, j = 0; j < NUM_STATS; j++) { allocatedArray[j] = 0; if (evBits & 1) k++; evBits >>= 1; } k = MAX_TOTAL_EVS / k; evBits = gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].evSpread; for (j = 0; j < NUM_STATS; j++) { if (evBits & 1) allocatedArray[j] = k; evBits >>= 1; } allocatedArray[NUM_STATS] += allocatedArray[STAT_HP]; for (j = 0; j < NUM_NATURE_STATS; j++) { nature = gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].nature; if (gNatureStatTable[nature][j] > 0) { allocatedArray[j + NUM_STATS + 1] += (allocatedArray[j + 1] * 110) / 100; } else if (gNatureStatTable[nature][j] < 0) { allocatedArray[j + NUM_STATS + 1] += (allocatedArray[j + 1] * 90) / 100; allocatedArray[j + NUM_STATS + NUM_NATURE_STATS + 2]++; } else { allocatedArray[j + NUM_STATS + 1] += allocatedArray[j + 1]; } } } for (j = 0, i = 0; i < NUM_STATS; i++) j += allocatedArray[i + NUM_STATS]; for (i = 0; i < NUM_STATS; i++) allocatedArray[i] = (allocatedArray[NUM_STATS + i] * 100) / j; } // Count the number of good/bad stats for the party // i is the number of good stats, j is the number of bad stats for (i = 0, j = 0, k = 0; k < NUM_STATS; k++) { // Any stat above 29 EVs is considered good if (allocatedArray[k] > 29) { // If 2 good stats have been found already, choose which to use if (i == 2) { if (allocatedArray[6] < allocatedArray[k]) { if (allocatedArray[7] < allocatedArray[k]) { if (allocatedArray[6] < allocatedArray[7]) { allocatedArray[6] = allocatedArray[7]; allocatedArray[7] = k; } else { allocatedArray[7] = k; } } else { allocatedArray[6] = allocatedArray[7]; allocatedArray[7] = k; } } else { if (allocatedArray[7] < allocatedArray[k]) allocatedArray[7] = k; } } else { allocatedArray[i + 6] = k; i++; } } // Any stat with 0 EVs is considered bad if (allocatedArray[k] == 0) { // If 2 bad stats have been found already, choose which to use if (j == 2) { if (allocatedArray[k + 12] >= 2 || ((allocatedArray[k + 12] == 1 && allocatedArray[12 + allocatedArray[8]] == 0 && allocatedArray[12 + allocatedArray[9]] == 0) ) ) { allocatedArray[8] = allocatedArray[9]; allocatedArray[9] = k; } else if (allocatedArray[k + 12] == 1 && allocatedArray[12 + allocatedArray[8]] == 0) { allocatedArray[8] = allocatedArray[9]; allocatedArray[9] = k; } else if (allocatedArray[k + 12] == 1 && allocatedArray[12 + allocatedArray[9]] == 0) { allocatedArray[9] = k; } } else { allocatedArray[j + 8] = k; j++; } } } // Get the string ID to display which stats are good/bad if (i == 2) i = sStatTextOffsets[allocatedArray[6]] + (allocatedArray[7] - (allocatedArray[6] + 1)) + DOME_TEXT_TWO_GOOD_STATS; else if (i == 1) i = allocatedArray[6] + DOME_TEXT_ONE_GOOD_STAT; else if (j == 2) i = sStatTextOffsets[allocatedArray[8]] + (allocatedArray[9] - (allocatedArray[8] + 1)) + DOME_TEXT_TWO_BAD_STATS; else if (j == 1) i = allocatedArray[8] + DOME_TEXT_ONE_BAD_STAT; else i = DOME_TEXT_WELL_BALANCED; // Print the stat text textPrinter.currentChar = sBattleDomeOpponentStatsTexts[i]; textPrinter.y = 36; textPrinter.currentY = 36; AddTextPrinter(&textPrinter, 0, NULL); Free(allocatedArray); } static int BufferDomeWinString(u8 matchNum, u8 *tournamentIds) { int i; u8 tournamentId; int winStringId = 0; int count = 0; // Get winners name for (i = sCompetitorRangeByMatch[matchNum][0]; i < sCompetitorRangeByMatch[matchNum][0] + sCompetitorRangeByMatch[matchNum][1]; i++) { tournamentId = sTourneyTreeTrainerIds2[i]; if (!DOME_TRAINERS[tournamentId].isEliminated) { tournamentIds[count] = tournamentId; if (DOME_TRAINERS[tournamentId].trainerId == TRAINER_PLAYER) StringCopy(gStringVar1, gSaveBlock2Ptr->playerName); else if (DOME_TRAINERS[tournamentId].trainerId == TRAINER_FRONTIER_BRAIN) CopyDomeBrainTrainerName(gStringVar1); else CopyDomeTrainerName(gStringVar1, DOME_TRAINERS[tournamentId].trainerId); count++; } } // Neither trainer has been eliminated, battle hasn't occurred yet if (count == 2) return DOME_TEXT_NO_WINNER_YET; for (i = sCompetitorRangeByMatch[matchNum][0]; i < sCompetitorRangeByMatch[matchNum][0] + sCompetitorRangeByMatch[matchNum][1]; i++) { tournamentId = sTourneyTreeTrainerIds2[i]; if (DOME_TRAINERS[tournamentId].isEliminated && DOME_TRAINERS[tournamentId].eliminatedAt >= sCompetitorRangeByMatch[matchNum][2]) { tournamentIds[count] = tournamentId; count++; if (DOME_TRAINERS[tournamentId].eliminatedAt == sCompetitorRangeByMatch[matchNum][2]) { // Set initial winStringId offset StringCopy(gStringVar2, gMoveNames[gSaveBlock2Ptr->frontier.domeWinningMoves[tournamentId]]); winStringId = DOME_TRAINERS[tournamentId].forfeited * 2; // (DOME_TEXT_WON_USING_MOVE - 1) or (DOME_TEXT_WON_ON_FORFEIT - 1) if (gSaveBlock2Ptr->frontier.domeWinningMoves[tournamentId] == MOVE_NONE && DOME_TRAINERS[tournamentId].forfeited == FALSE) winStringId = DOME_TEXT_WON_NO_MOVES - 1; } else { if (DOME_TRAINERS[tournamentId].trainerId == TRAINER_PLAYER) StringCopy(gStringVar1, gSaveBlock2Ptr->playerName); else if (DOME_TRAINERS[tournamentId].trainerId == TRAINER_FRONTIER_BRAIN) CopyDomeBrainTrainerName(gStringVar1); else CopyDomeTrainerName(gStringVar1, DOME_TRAINERS[tournamentId].trainerId); } } if (count == 2) break; } if (matchNum == DOME_TOURNAMENT_MATCHES_COUNT - 1) return winStringId + 2; // use DOME_TEXT_CHAMP_* else return winStringId + 1; // use DOME_TEXT_WON_* } static void DisplayMatchInfoOnCard(u8 flags, u8 matchNo) { struct TextPrinterTemplate textPrinter; int tournamentIds[2]; int trainerIds[2]; bool32 lost[2]; int i; int winStringId = 0; int arrId = 0; int windowId = 0; int x = 0, y = 0; u8 palSlot = 0; if (flags & CARD_ALTERNATE_SLOT) arrId = 2 * (FRONTIER_PARTY_SIZE + 1), windowId = 9, palSlot = 2; if (flags & MOVE_CARD_RIGHT) x = DISPLAY_WIDTH + 16; if (flags & MOVE_CARD_DOWN) y = DISPLAY_HEIGHT; if (flags & MOVE_CARD_LEFT) x = -(DISPLAY_WIDTH + 16); if (flags & MOVE_CARD_UP) y = -DISPLAY_HEIGHT; // Copy trainers information to handy arrays. winStringId = BufferDomeWinString(matchNo, sInfoCard->tournamentIds); for (i = 0; i < NUM_INFOCARD_TRAINERS; i++) { tournamentIds[i] = sInfoCard->tournamentIds[i]; trainerIds[i] = DOME_TRAINERS[tournamentIds[i]].trainerId; if (DOME_TRAINERS[tournamentIds[i]].eliminatedAt <= sCompetitorRangeByMatch[matchNo][2] && DOME_TRAINERS[tournamentIds[i]].isEliminated) lost[i] = TRUE; else lost[i] = FALSE; } // Draw left trainer sprite. if (trainerIds[0] == TRAINER_PLAYER) sInfoCard->spriteIds[arrId] = CreateTrainerPicSprite(PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender), TRUE, x + 48, y + 88, palSlot + 12, TAG_NONE); else if (trainerIds[0] == TRAINER_FRONTIER_BRAIN) sInfoCard->spriteIds[arrId] = CreateTrainerPicSprite(GetDomeBrainTrainerPicId(), TRUE, x + 48, y + 88, palSlot + 12, TAG_NONE); else sInfoCard->spriteIds[arrId] = CreateTrainerPicSprite(GetFrontierTrainerFrontSpriteId(trainerIds[0]), TRUE, x + 48, y + 88, palSlot + 12, TAG_NONE); if (flags & MOVE_CARD) gSprites[sInfoCard->spriteIds[arrId]].invisible = TRUE; if (lost[0]) gSprites[sInfoCard->spriteIds[arrId]].oam.paletteNum = 3; // Draw right trainer sprite. if (trainerIds[1] == TRAINER_PLAYER) sInfoCard->spriteIds[1 + arrId] = CreateTrainerPicSprite(PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender), TRUE, x + 192, y + 88, palSlot + 13, TAG_NONE); else if (trainerIds[1] == TRAINER_FRONTIER_BRAIN) sInfoCard->spriteIds[1 + arrId] = CreateTrainerPicSprite(GetDomeBrainTrainerPicId(), TRUE, x + 192, y + 88, palSlot + 13, TAG_NONE); else sInfoCard->spriteIds[1 + arrId] = CreateTrainerPicSprite(GetFrontierTrainerFrontSpriteId(trainerIds[1]), TRUE, x + 192, y + 88, palSlot + 13, TAG_NONE); if (flags & MOVE_CARD) gSprites[sInfoCard->spriteIds[1 + arrId]].invisible = TRUE; if (lost[1]) gSprites[sInfoCard->spriteIds[1 + arrId]].oam.paletteNum = 3; // Draw left trainer's pokemon icons. for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { if (trainerIds[0] == TRAINER_PLAYER) { sInfoCard->spriteIds[2 + i + arrId] = CreateMonIcon(DOME_MONS[tournamentIds[0]][i], SpriteCb_MonIcon, x | sLeftTrainerMonX[i], y + sLeftTrainerMonY[i], 0, 0, TRUE); gSprites[sInfoCard->spriteIds[2 + i + arrId]].oam.priority = 0; } else if (trainerIds[0] == TRAINER_FRONTIER_BRAIN) { sInfoCard->spriteIds[2 + i + arrId] = CreateMonIcon(DOME_MONS[tournamentIds[0]][i], SpriteCb_MonIcon, x | sLeftTrainerMonX[i], y + sLeftTrainerMonY[i], 0, 0, TRUE); gSprites[sInfoCard->spriteIds[2 + i + arrId]].oam.priority = 0; } else { sInfoCard->spriteIds[2 + i + arrId] = CreateMonIcon(gFacilityTrainerMons[DOME_MONS[tournamentIds[0]][i]].species, SpriteCb_MonIcon, x | sLeftTrainerMonX[i], y + sLeftTrainerMonY[i], 0, 0, TRUE); gSprites[sInfoCard->spriteIds[2 + i + arrId]].oam.priority = 0; } if (flags & MOVE_CARD) gSprites[sInfoCard->spriteIds[2 + i + arrId]].invisible = TRUE; if (lost[0]) { gSprites[sInfoCard->spriteIds[2 + i + arrId]].oam.paletteNum = 3; gSprites[sInfoCard->spriteIds[2 + i + arrId]].sMonIconStill = TRUE; } } // Draw right trainer's pokemon icons. for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { if (trainerIds[1] == TRAINER_PLAYER) { sInfoCard->spriteIds[5 + i + arrId] = CreateMonIcon(DOME_MONS[tournamentIds[1]][i], SpriteCb_MonIcon, x | sRightTrainerMonX[i], y + sRightTrainerMonY[i], 0, 0, TRUE); gSprites[sInfoCard->spriteIds[5 + i + arrId]].oam.priority = 0; } else if (trainerIds[1] == TRAINER_FRONTIER_BRAIN) { sInfoCard->spriteIds[5 + i + arrId] = CreateMonIcon(DOME_MONS[tournamentIds[1]][i], SpriteCb_MonIcon, x | sRightTrainerMonX[i], y + sRightTrainerMonY[i], 0, 0, TRUE); gSprites[sInfoCard->spriteIds[5 + i + arrId]].oam.priority = 0; } else { sInfoCard->spriteIds[5 + i + arrId] = CreateMonIcon(gFacilityTrainerMons[DOME_MONS[tournamentIds[1]][i]].species, SpriteCb_MonIcon, x | sRightTrainerMonX[i], y + sRightTrainerMonY[i], 0, 0, TRUE); gSprites[sInfoCard->spriteIds[5 + i + arrId]].oam.priority = 0; } if (flags & MOVE_CARD) gSprites[sInfoCard->spriteIds[5 + i + arrId]].invisible = TRUE; if (lost[1]) { gSprites[sInfoCard->spriteIds[5 + i + arrId]].oam.paletteNum = 3; gSprites[sInfoCard->spriteIds[5 + i + arrId]].sMonIconStill = TRUE; } } // Print the win string (or 'Let the battle begin!'). textPrinter.x = 0; textPrinter.y = 2; textPrinter.currentX = textPrinter.x; textPrinter.currentY = textPrinter.y; textPrinter.letterSpacing = 0; textPrinter.lineSpacing = 0; textPrinter.unk = 0; textPrinter.fgColor = TEXT_DYNAMIC_COLOR_5; textPrinter.bgColor = TEXT_COLOR_TRANSPARENT; textPrinter.shadowColor = TEXT_DYNAMIC_COLOR_4; StringExpandPlaceholders(gStringVar4, sBattleDomeWinTexts[winStringId]); textPrinter.currentChar = gStringVar4; textPrinter.windowId = windowId + 8; textPrinter.fontId = FONT_NORMAL; PutWindowTilemap(windowId + 8); CopyWindowToVram(windowId + 8, COPYWIN_FULL); textPrinter.currentX = 0; textPrinter.currentY = textPrinter.y = 0; AddTextPrinter(&textPrinter, 0, NULL); // Print left trainer's name. if (trainerIds[0] == TRAINER_PLAYER) StringCopy(gStringVar1, gSaveBlock2Ptr->playerName); else if (trainerIds[0] == TRAINER_FRONTIER_BRAIN) CopyDomeBrainTrainerName(gStringVar1); else CopyDomeTrainerName(gStringVar1, trainerIds[0]); textPrinter.fontId = FONT_SHORT; textPrinter.letterSpacing = 2; textPrinter.currentChar = gStringVar1; textPrinter.windowId = windowId + 6; textPrinter.currentX = GetStringCenterAlignXOffsetWithLetterSpacing(textPrinter.fontId, textPrinter.currentChar, 0x40, textPrinter.letterSpacing); textPrinter.currentY = textPrinter.y = 2; PutWindowTilemap(windowId + 6); CopyWindowToVram(windowId + 6, COPYWIN_FULL); AddTextPrinter(&textPrinter, 0, NULL); // Print right trainer's name. if (trainerIds[1] == TRAINER_PLAYER) StringCopy(gStringVar1, gSaveBlock2Ptr->playerName); else if (trainerIds[1] == TRAINER_FRONTIER_BRAIN) CopyDomeBrainTrainerName(gStringVar1); else CopyDomeTrainerName(gStringVar1, trainerIds[1]); textPrinter.currentChar = gStringVar1; textPrinter.windowId = windowId + 7; textPrinter.currentX = GetStringCenterAlignXOffsetWithLetterSpacing(textPrinter.fontId, textPrinter.currentChar, 0x40, textPrinter.letterSpacing); textPrinter.currentY = textPrinter.y = 2; PutWindowTilemap(windowId + 7); CopyWindowToVram(windowId + 7, COPYWIN_FULL); AddTextPrinter(&textPrinter, 0, NULL); // Print match number. textPrinter.letterSpacing = 0; textPrinter.currentChar = sBattleDomeMatchNumberTexts[matchNo]; textPrinter.windowId = windowId + 5; textPrinter.currentX = GetStringCenterAlignXOffsetWithLetterSpacing(textPrinter.fontId, textPrinter.currentChar, 0xA0, textPrinter.letterSpacing); textPrinter.currentY = textPrinter.y = 2; PutWindowTilemap(windowId + 5); CopyWindowToVram(windowId + 5, COPYWIN_FULL); AddTextPrinter(&textPrinter, 0, NULL); } static void ShowDomeTourneyTree(void) { u8 taskId = CreateTask(Task_ShowTourneyTree, 0); gTasks[taskId].tState = 0; gTasks[taskId].tNotInteractive = FALSE; gTasks[taskId].data[2] = 2; gTasks[taskId].tIsPrevTourneyTree = FALSE; SetMainCallback2(CB2_TourneyTree); } // To show the results of the last tourney on the computer in the lobby static void ShowPreviousDomeTourneyTree(void) { u8 taskId; SetFacilityTrainerAndMonPtrs(); gSaveBlock2Ptr->frontier.lvlMode = gSaveBlock2Ptr->frontier.domeLvlMode - 1; gSaveBlock2Ptr->frontier.curChallengeBattleNum = DOME_FINAL; taskId = CreateTask(Task_ShowTourneyTree, 0); gTasks[taskId].tState = 0; gTasks[taskId].tNotInteractive = FALSE; gTasks[taskId].data[2] = 2; gTasks[taskId].tIsPrevTourneyTree = TRUE; SetMainCallback2(CB2_TourneyTree); } // Task states for Task_HandleTourneyTreeInput #define STATE_FADE_IN 0 #define STATE_WAIT_FADE 1 #define STATE_GET_INPUT 2 #define STATE_SHOW_INFOCARD_TRAINER 3 #define STATE_SHOW_INFOCARD_MATCH 5 #define STATE_CLOSE_TOURNEY_TREE 7 static void Task_HandleTourneyTreeInput(u8 taskId) { u8 newTaskId = 0; int spriteId = gTasks[taskId].data[1]; switch (gTasks[taskId].tState) { case STATE_FADE_IN: if (!gPaletteFade.active) { BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK); gTasks[taskId].tState = STATE_WAIT_FADE; StartSpriteAnim(&gSprites[spriteId], 1); } break; case STATE_WAIT_FADE: if (!gPaletteFade.active) gTasks[taskId].tState = STATE_GET_INPUT; break; case STATE_GET_INPUT: switch (UpdateTourneyTreeCursor(taskId)) { case TOURNEY_TREE_SELECTED_CLOSE: default: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); gTasks[taskId].tState = STATE_CLOSE_TOURNEY_TREE; break; case TOURNEY_TREE_NO_SELECTION: break; case TOURNEY_TREE_SELECTED_TRAINER: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); gTasks[taskId].tState = STATE_SHOW_INFOCARD_TRAINER; break; case TOURNEY_TREE_SELECTED_MATCH: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); gTasks[taskId].tState = STATE_SHOW_INFOCARD_MATCH; break; } break; case STATE_SHOW_INFOCARD_TRAINER: if (!gPaletteFade.active) { FreeAllWindowBuffers(); ScanlineEffect_Stop(); FREE_AND_SET_NULL(sTilemapBuffer); newTaskId = CreateTask(Task_ShowTourneyInfoCard, 0); gTasks[newTaskId].tState = 0; gTasks[newTaskId].tTournamentId = sTourneyTreeTrainerIds[spriteId]; gTasks[newTaskId].tMode = INFOCARD_TRAINER; gTasks[newTaskId].tPrevTaskId = taskId; gTasks[taskId].tState = STATE_SHOW_INFOCARD_TRAINER + 1; sInfoCard->pos = 0; } break; case STATE_SHOW_INFOCARD_TRAINER + 1: break; case STATE_SHOW_INFOCARD_MATCH: if (!gPaletteFade.active) { FreeAllWindowBuffers(); ScanlineEffect_Stop(); FREE_AND_SET_NULL(sTilemapBuffer); newTaskId = CreateTask(Task_ShowTourneyInfoCard, 0); gTasks[newTaskId].tState = 0; gTasks[newTaskId].tTournamentId = spriteId - DOME_TOURNAMENT_TRAINERS_COUNT; gTasks[newTaskId].tMode = INFOCARD_MATCH; gTasks[newTaskId].tPrevTaskId = taskId; gTasks[taskId].tState = STATE_SHOW_INFOCARD_MATCH + 1; } break; case STATE_SHOW_INFOCARD_MATCH + 1: break; case STATE_CLOSE_TOURNEY_TREE: if (!gPaletteFade.active) { FreeAllWindowBuffers(); ScanlineEffect_Stop(); FREE_AND_SET_NULL(sTilemapBuffer); SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); DestroyTask(gTasks[taskId].data[7]); DestroyTask(taskId); } break; } } // undefine task states for Task_HandleTourneyTreeInput #undef STATE_FADE_IN #undef STATE_WAIT_FADE #undef STATE_GET_INPUT #undef STATE_SHOW_INFOCARD_TRAINER #undef STATE_SHOW_INFOCARD_MATCH #undef STATE_CLOSE_TOURNEY_TREE #define MOVE_DIR_UP 0 #define MOVE_DIR_DOWN 1 #define MOVE_DIR_LEFT 2 #define MOVE_DIR_RIGHT 3 #define MOVE_DIR_NONE 4 // Move the tourney tree cursor // The 'cursor' is actually just which button sprite is currently doing the 'selected' animation static u8 UpdateTourneyTreeCursor(u8 taskId) { u8 selection = TOURNEY_TREE_NO_SELECTION; int direction = MOVE_DIR_NONE; int tourneyTreeCursorSpriteId = gTasks[taskId].data[1]; int roundId = gSaveBlock2Ptr->frontier.curChallengeBattleNum; if (gMain.newKeys == B_BUTTON || (JOY_NEW(A_BUTTON) && tourneyTreeCursorSpriteId == TOURNEY_TREE_CLOSE_BUTTON)) { PlaySE(SE_SELECT); selection = TOURNEY_TREE_SELECTED_CLOSE; } else if (JOY_NEW(A_BUTTON)) { if (tourneyTreeCursorSpriteId < DOME_TOURNAMENT_TRAINERS_COUNT) { PlaySE(SE_SELECT); selection = TOURNEY_TREE_SELECTED_TRAINER; } else { PlaySE(SE_SELECT); selection = TOURNEY_TREE_SELECTED_MATCH; } } else { if (gMain.newKeys == DPAD_UP && sTourneyTreeCursorMovementMap[tourneyTreeCursorSpriteId][roundId][0] != 0xFF) direction = MOVE_DIR_UP; else if (gMain.newKeys == DPAD_DOWN && sTourneyTreeCursorMovementMap[tourneyTreeCursorSpriteId][roundId][1] != 0xFF) direction = MOVE_DIR_DOWN; else if (gMain.newKeys == DPAD_LEFT && sTourneyTreeCursorMovementMap[tourneyTreeCursorSpriteId][roundId][2] != 0xFF) direction = MOVE_DIR_LEFT; else if (gMain.newKeys == DPAD_RIGHT && sTourneyTreeCursorMovementMap[tourneyTreeCursorSpriteId][roundId][3] != 0xFF) direction = MOVE_DIR_RIGHT; } if (direction != MOVE_DIR_NONE) { PlaySE(SE_SELECT); StartSpriteAnim(&gSprites[tourneyTreeCursorSpriteId], 0); // Do unselected sprite anim tourneyTreeCursorSpriteId = sTourneyTreeCursorMovementMap[tourneyTreeCursorSpriteId][roundId][direction]; StartSpriteAnim(&gSprites[tourneyTreeCursorSpriteId], 1); // Do selected sprite anim gTasks[taskId].data[1] = tourneyTreeCursorSpriteId; } return selection; } #undef MOVE_DIR_UP #undef MOVE_DIR_DOWN #undef MOVE_DIR_LEFT #undef MOVE_DIR_RIGHT #undef MOVE_DIR_NONE // Shows the results of the just-completed round for the current tourney static void ShowNonInteractiveDomeTourneyTree(void) { u8 taskId = CreateTask(Task_ShowTourneyTree, 0); gTasks[taskId].tState = 0; gTasks[taskId].tNotInteractive = TRUE; gTasks[taskId].data[2] = 2; gTasks[taskId].tIsPrevTourneyTree = FALSE; SetMainCallback2(CB2_TourneyTree); } static void ResolveDomeRoundWinners(void) { int i; if (gSpecialVar_0x8005 == DOME_PLAYER_WON_MATCH) { DOME_TRAINERS[TrainerIdToTournamentId(gTrainerBattleOpponent_A)].isEliminated = TRUE; DOME_TRAINERS[TrainerIdToTournamentId(gTrainerBattleOpponent_A)].eliminatedAt = gSaveBlock2Ptr->frontier.curChallengeBattleNum; gSaveBlock2Ptr->frontier.domeWinningMoves[TrainerIdToTournamentId(gTrainerBattleOpponent_A)] = gBattleResults.lastUsedMovePlayer; // If the player's match was the final one, no NPC vs NPC matches to decide if (gSaveBlock2Ptr->frontier.curChallengeBattleNum < DOME_FINAL) DecideRoundWinners(gSaveBlock2Ptr->frontier.curChallengeBattleNum); } else // DOME_PLAYER_LOST_MATCH or DOME_PLAYER_RETIRED { DOME_TRAINERS[TrainerIdToTournamentId(TRAINER_PLAYER)].isEliminated = TRUE; DOME_TRAINERS[TrainerIdToTournamentId(TRAINER_PLAYER)].eliminatedAt = gSaveBlock2Ptr->frontier.curChallengeBattleNum; gSaveBlock2Ptr->frontier.domeWinningMoves[TrainerIdToTournamentId(TRAINER_PLAYER)] = gBattleResults.lastUsedMoveOpponent; if (gBattleOutcome == B_OUTCOME_FORFEITED || gSpecialVar_0x8005 == DOME_PLAYER_RETIRED) DOME_TRAINERS[TrainerIdToTournamentId(TRAINER_PLAYER)].forfeited = TRUE; // Player lost, decide remaining outcome of tournament for (i = gSaveBlock2Ptr->frontier.curChallengeBattleNum; i < DOME_ROUNDS_COUNT; i++) DecideRoundWinners(i); } } // Decides the winning move of an NPC vs NPC match static u16 GetWinningMove(int winnerTournamentId, int loserTournamentId, u8 roundId) { int i, j, k; int moveScores[MAX_MON_MOVES * FRONTIER_PARTY_SIZE]; u16 moveIds[MAX_MON_MOVES * FRONTIER_PARTY_SIZE]; u16 bestScore = 0; u16 bestId = 0; int movePower = 0; SetFacilityPtrsGetLevel(); // Calc move points of all 4 moves for all 3 pokemon hitting all 3 target mons. for (i = 0; i < FRONTIER_PARTY_SIZE; i++) { for (j = 0; j < MAX_MON_MOVES; j++) { // TODO: Clean this up, looks like a different data structure (2D array) moveScores[i * MAX_MON_MOVES + j] = 0; if (DOME_TRAINERS[winnerTournamentId].trainerId == TRAINER_FRONTIER_BRAIN) moveIds[i * MAX_MON_MOVES + j] = GetFrontierBrainMonMove(i, j); else moveIds[i * MAX_MON_MOVES + j] = gFacilityTrainerMons[DOME_MONS[winnerTournamentId][i]].moves[j]; movePower = gBattleMoves[moveIds[i * MAX_MON_MOVES + j]].power; if (movePower == 0) movePower = 40; else if (movePower == 1) movePower = 60; else if (moveIds[i * MAX_MON_MOVES + j] == MOVE_SELF_DESTRUCT || moveIds[i * MAX_MON_MOVES + j] == MOVE_EXPLOSION) movePower /= 2; for (k = 0; k < FRONTIER_PARTY_SIZE; k++) { u32 var = 0; u16 targetSpecies = SPECIES_NONE; u16 targetAbility = ABILITY_NONE; do { var = Random32(); } while (gFacilityTrainerMons[DOME_MONS[loserTournamentId][k]].nature != GetNatureFromPersonality(var)); targetSpecies = gFacilityTrainerMons[DOME_MONS[loserTournamentId][k]].species; if (var & 1) targetAbility = gBaseStats[targetSpecies].abilities[1]; else targetAbility = gBaseStats[targetSpecies].abilities[0]; var = AI_TypeCalc(moveIds[i * MAX_MON_MOVES + j], targetSpecies, targetAbility); if (var & MOVE_RESULT_NOT_VERY_EFFECTIVE && var & MOVE_RESULT_SUPER_EFFECTIVE) moveScores[i * MAX_MON_MOVES + j] += movePower; else if (var & MOVE_RESULT_NO_EFFECT) moveScores[i * MAX_MON_MOVES + j] += 0; else if (var & MOVE_RESULT_SUPER_EFFECTIVE) moveScores[i * MAX_MON_MOVES + j] += movePower * 2; else if (var & MOVE_RESULT_NOT_VERY_EFFECTIVE) moveScores[i * MAX_MON_MOVES + j] += movePower / 2; else moveScores[i * MAX_MON_MOVES + j] += movePower; } if (bestScore < moveScores[i * MAX_MON_MOVES + j]) { bestId = i * MAX_MON_MOVES + j; bestScore = moveScores[i * MAX_MON_MOVES + j]; } else if (bestScore == moveScores[i * MAX_MON_MOVES + j]) { if (moveIds[bestId] < moveIds[i * MAX_MON_MOVES + j]) // Why not use (Random() & 1) instead of promoting moves with a higher id? bestId = i * MAX_MON_MOVES + j; } } } j = bestId; do { for (i = 0; i < roundId - 1; i++) { if (gSaveBlock2Ptr->frontier.domeWinningMoves[GetOpposingNPCTournamentIdByRound(winnerTournamentId, i)] == moveIds[j]) break; } if (i != roundId - 1) { moveScores[j] = 0; bestScore = 0; j = 0; for (k = 0; k < MAX_MON_MOVES * FRONTIER_PARTY_SIZE; k++) j += moveScores[k]; if (j == 0) break; j = 0; for (k = 0; k < MAX_MON_MOVES * FRONTIER_PARTY_SIZE; k++) { if (bestScore < moveScores[k]) { j = k; bestScore = moveScores[k]; } else if (bestScore == moveScores[k] && moveIds[j] < moveIds[k]) // Yes, these conditions are redundant { j = k; bestScore = moveScores[k]; } } } } while (i != roundId - 1); if (moveScores[j] == 0) j = bestId; return moveIds[j]; } static void Task_ShowTourneyTree(u8 taskId) { int i; struct TextPrinterTemplate textPrinter; int notInteractive = gTasks[taskId].tNotInteractive; int r4 = gTasks[taskId].data[2]; switch (gTasks[taskId].tState) { case 0: SetHBlankCallback(NULL); SetVBlankCallback(NULL); EnableInterrupts(INTR_FLAG_HBLANK | INTR_FLAG_VBLANK); CpuFill32(0, (void *)VRAM, VRAM_SIZE); ResetBgsAndClearDma3BusyFlags(0); InitBgsFromTemplates(0, sTourneyTreeBgTemplates, ARRAY_COUNT(sTourneyTreeBgTemplates)); InitWindows(sTourneyTreeWindowTemplates); DeactivateAllTextPrinters(); gBattle_BG0_X = 0; gBattle_BG0_Y = 0; gBattle_BG1_X = 0; gBattle_BG1_Y = 0; ChangeBgX(2, 0, BG_COORD_SET); ChangeBgY(2, 0, BG_COORD_SET); ChangeBgX(3, 0, BG_COORD_SET); ChangeBgY(3, 0xB00, BG_COORD_SET); gTasks[taskId].tState++; break; case 1: SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); SetGpuReg(REG_OFFSET_BLDY, 0); SetGpuReg(REG_OFFSET_MOSAIC, 0); SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(88, 96)); SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(0, DISPLAY_HEIGHT - 1)); SetGpuReg(REG_OFFSET_WIN1H, WIN_RANGE(144, 152)); SetGpuReg(REG_OFFSET_WIN1V, WIN_RANGE(0, DISPLAY_HEIGHT - 1)); SetGpuReg(REG_OFFSET_WININ, 0); SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR); ResetPaletteFade(); ResetSpriteData(); FreeAllSpritePalettes(); gTasks[taskId].tState++; break; case 2: sTilemapBuffer = AllocZeroed(BG_SCREEN_SIZE); LZDecompressWram(gDomeTourneyLineMask_Tilemap, sTilemapBuffer); SetBgTilemapBuffer(1, sTilemapBuffer); CopyBgTilemapBufferToVram(1); DecompressAndLoadBgGfxUsingHeap(1, gDomeTourneyBg_Gfx, 0x2000, 0, 0); DecompressAndLoadBgGfxUsingHeap(2, gDomeTourneyLine_Gfx, 0x2000, 0, 0); DecompressAndLoadBgGfxUsingHeap(2, gDomeTourneyLineDown_Tilemap, 0x2000, 0, 1); DecompressAndLoadBgGfxUsingHeap(3, gDomeTourneyLineUp_Tilemap, 0x2000, 0, 1); LoadCompressedPalette(gDomeTourneyTree_Pal, 0, 0x200); LoadCompressedPalette(gDomeTourneyTreeButtons_Pal, 0x100, 0x200); LoadCompressedPalette(gBattleWindowTextPalette, 0xF0, 0x20); CpuFill32(0, gPlttBufferFaded, 0x400); ShowBg(0); ShowBg(1); ShowBg(2); ShowBg(3); gTasks[taskId].tState++; break; case 3: LoadCompressedSpriteSheet(sTourneyTreeButtonsSpriteSheet); if (notInteractive == FALSE) { for (i = 0; i < ARRAY_COUNT(sTourneyTreePokeballCoords); i++) CreateSprite(&sTourneyTreePokeballSpriteTemplate, sTourneyTreePokeballCoords[i][0], sTourneyTreePokeballCoords[i][1], 0); if (gTasks[taskId].tIsPrevTourneyTree) CreateSprite(&sExitButtonSpriteTemplate, 218, 12, 0); else CreateSprite(&sCancelButtonSpriteTemplate, 218, 12, 0); } SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_BG_ALL_ON | DISPCNT_OBJ_ON | DISPCNT_WIN0_ON | DISPCNT_WIN1_ON | DISPCNT_OBJ_1D_MAP); gTasks[taskId].tState++; break; case 4: textPrinter.fontId = FONT_SHORT; textPrinter.currentChar = gText_BattleTourney; textPrinter.windowId = 2; textPrinter.x = 0; textPrinter.y = 0; textPrinter.letterSpacing = 2; textPrinter.lineSpacing = 0; textPrinter.currentX = GetStringCenterAlignXOffsetWithLetterSpacing(textPrinter.fontId, textPrinter.currentChar, 0x70, textPrinter.letterSpacing); textPrinter.currentY = 1; textPrinter.unk = 0; textPrinter.fgColor = TEXT_DYNAMIC_COLOR_5; textPrinter.bgColor = TEXT_COLOR_TRANSPARENT; textPrinter.shadowColor = TEXT_DYNAMIC_COLOR_4; AddTextPrinter(&textPrinter, 0, NULL); for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { int roundId, var2; CopyDomeTrainerName(gDisplayedStringBattle, DOME_TRAINERS[i].trainerId); if (notInteractive == TRUE) { if (DOME_TRAINERS[i].isEliminated) { if (DOME_TRAINERS[i].eliminatedAt != DOME_ROUND1) { var2 = DOME_TRAINERS[i].eliminatedAt - 1; DrawTourneyAdvancementLine(i, var2); } } else if (gSaveBlock2Ptr->frontier.curChallengeBattleNum != DOME_ROUND2) { DrawTourneyAdvancementLine(i, gSaveBlock2Ptr->frontier.curChallengeBattleNum - 2); } } else if (notInteractive == FALSE) { if (DOME_TRAINERS[i].isEliminated) { if (DOME_TRAINERS[i].eliminatedAt != DOME_ROUND1) { var2 = DOME_TRAINERS[i].eliminatedAt - 1; DrawTourneyAdvancementLine(i, var2); } } else if (gSaveBlock2Ptr->frontier.curChallengeBattleNum != DOME_ROUND1) { if (gTasks[taskId].tIsPrevTourneyTree) var2 = gSaveBlock2Ptr->frontier.curChallengeBattleNum; else var2 = gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1; DrawTourneyAdvancementLine(i, var2); } } if (gTasks[taskId].tIsPrevTourneyTree) roundId = gSaveBlock2Ptr->frontier.curChallengeBattleNum; else roundId = gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1; if ( ((notInteractive == TRUE && DOME_TRAINERS[i].eliminatedAt < gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1) || (notInteractive == FALSE && DOME_TRAINERS[i].eliminatedAt <= roundId)) && DOME_TRAINERS[i].isEliminated) { if (DOME_TRAINERS[i].trainerId == TRAINER_PLAYER) { textPrinter.fgColor = TEXT_COLOR_LIGHT_GRAY; textPrinter.shadowColor = TEXT_COLOR_RED; } else { textPrinter.fgColor = TEXT_DYNAMIC_COLOR_2; textPrinter.shadowColor = TEXT_DYNAMIC_COLOR_4; } } else { if (DOME_TRAINERS[i].trainerId == TRAINER_PLAYER) { textPrinter.fgColor = TEXT_COLOR_LIGHT_GRAY; textPrinter.shadowColor = TEXT_COLOR_RED; } else { textPrinter.fgColor = TEXT_DYNAMIC_COLOR_5; textPrinter.shadowColor = TEXT_DYNAMIC_COLOR_4; } } if (sTrainerNamePositions[i][0] == 0) textPrinter.currentX = GetStringWidthDifference(textPrinter.fontId, gDisplayedStringBattle, 0x3D, textPrinter.letterSpacing); else textPrinter.currentX = 3; textPrinter.currentChar = gDisplayedStringBattle; textPrinter.windowId = sTrainerNamePositions[i][0]; textPrinter.currentY = sTrainerNamePositions[i][1]; AddTextPrinter(&textPrinter, 0, NULL); } gTasks[taskId].tState++; break; case 5: PutWindowTilemap(0); PutWindowTilemap(1); PutWindowTilemap(2); CopyWindowToVram(0, COPYWIN_FULL); CopyWindowToVram(1, COPYWIN_FULL); CopyWindowToVram(2, COPYWIN_FULL); SetHBlankCallback(HblankCb_TourneyTree); SetVBlankCallback(VblankCb_TourneyTree); if (r4 == 2) { if (notInteractive == FALSE) { i = CreateTask(Task_HandleTourneyTreeInput, 0); gTasks[i].data[0] = notInteractive; gTasks[i].data[1] = notInteractive; gTasks[i].data[6] = gTasks[taskId].tIsPrevTourneyTree; } else { i = CreateTask(Task_HandleStaticTourneyTreeInput, 0); gTasks[i].data[0] = 0; } } else { i = gTasks[taskId].data[3]; gTasks[i].tState = 0; } ScanlineEffect_Clear(); i = 0; while (i < 91) { gScanlineEffectRegBuffers[0][i] = BGCNT_PRIORITY(2) | BGCNT_SCREENBASE(31) | BGCNT_16COLOR | BGCNT_CHARBASE(2) | BGCNT_TXT256x256; gScanlineEffectRegBuffers[1][i] = BGCNT_PRIORITY(2) | BGCNT_SCREENBASE(31) | BGCNT_16COLOR | BGCNT_CHARBASE(2) | BGCNT_TXT256x256; i++; } while (i < 160) { gScanlineEffectRegBuffers[0][i] = BGCNT_PRIORITY(1) | BGCNT_SCREENBASE(31) | BGCNT_16COLOR | BGCNT_CHARBASE(2) | BGCNT_TXT256x256; gScanlineEffectRegBuffers[1][i] = BGCNT_PRIORITY(1) | BGCNT_SCREENBASE(31) | BGCNT_16COLOR | BGCNT_CHARBASE(2) | BGCNT_TXT256x256; i++; } ScanlineEffect_SetParams(sTourneyTreeScanlineEffectParams); DestroyTask(taskId); break; } } static void DrawTourneyAdvancementLine(u8 tournamentId, u8 roundId) { int i; const struct TourneyTreeLineSection *lineSection = sTourneyTreeLineSections[tournamentId][roundId]; for (i = 0; i < sTourneyTreeLineSectionArrayCounts[tournamentId][roundId]; i++) CopyToBgTilemapBufferRect_ChangePalette(1, &lineSection[i].src, lineSection[i].x, lineSection[i].y, 1, 1, 17); CopyBgTilemapBufferToVram(1); } #define STATE_FADE_IN 0 #define STATE_SHOW_RESULTS 1 #define STATE_DELAY 2 #define STATE_WAIT_FOR_INPUT 3 #define STATE_CLOSE_TOURNEY_TREE 4 // The non-interactive tourney tree that's shown when a round is completed static void Task_HandleStaticTourneyTreeInput(u8 taskId) { int i; struct TextPrinterTemplate textPrinter; switch (gTasks[taskId].tState) { case STATE_FADE_IN: BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK); gTasks[taskId].tState = STATE_SHOW_RESULTS; break; case STATE_SHOW_RESULTS: if (!gPaletteFade.active) { gTasks[taskId].tState = STATE_DELAY; gTasks[taskId].data[3] = 64; textPrinter.fontId = FONT_SHORT; textPrinter.x = 0; textPrinter.y = 0; textPrinter.letterSpacing = 2; textPrinter.lineSpacing = 0; textPrinter.unk = 0; textPrinter.fgColor = TEXT_DYNAMIC_COLOR_2; textPrinter.bgColor = TEXT_COLOR_TRANSPARENT; textPrinter.shadowColor = TEXT_DYNAMIC_COLOR_4; // Update the advancement lines and gray out eliminated trainer names for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { CopyDomeTrainerName(gDisplayedStringBattle, DOME_TRAINERS[i].trainerId); if (DOME_TRAINERS[i].eliminatedAt == gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1 && DOME_TRAINERS[i].isEliminated) { if (sTrainerNamePositions[i][0] == 0) textPrinter.currentX = GetStringWidthDifference(textPrinter.fontId, gDisplayedStringBattle, 0x3D, textPrinter.letterSpacing); else textPrinter.currentX = 3; textPrinter.currentChar = gDisplayedStringBattle; textPrinter.windowId = sTrainerNamePositions[i][0]; textPrinter.currentY = sTrainerNamePositions[i][1]; AddTextPrinter(&textPrinter, 0, NULL); } if (!DOME_TRAINERS[i].isEliminated) { int roundId = gSaveBlock2Ptr->frontier.curChallengeBattleNum - 1; DrawTourneyAdvancementLine(i, roundId); } } } break; case STATE_DELAY: if (--gTasks[taskId].data[3] == 0) gTasks[taskId].tState = STATE_WAIT_FOR_INPUT; break; case STATE_WAIT_FOR_INPUT: if (JOY_NEW(A_BUTTON | B_BUTTON)) { BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); gTasks[taskId].tState = STATE_CLOSE_TOURNEY_TREE; } break; case STATE_CLOSE_TOURNEY_TREE: if (!gPaletteFade.active) { SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); DestroyTask(taskId); } break; } } #undef STATE_FADE_IN #undef STATE_SHOW_RESULTS #undef STATE_DELAY #undef STATE_WAIT_FOR_INPUT #undef STATE_CLOSE_TOURNEY_TREE static void CB2_TourneyTree(void) { AnimateSprites(); BuildOamBuffer(); RunTextPrinters(); UpdatePaletteFade(); RunTasks(); } static void VblankCb_TourneyInfoCard(void) { ChangeBgX(3, 0x80, BG_COORD_ADD); ChangeBgY(3, 0x80, BG_COORD_SUB); SetGpuReg(REG_OFFSET_BG0HOFS, gBattle_BG0_X); SetGpuReg(REG_OFFSET_BG0VOFS, gBattle_BG0_Y); SetGpuReg(REG_OFFSET_BG1HOFS, gBattle_BG1_X); SetGpuReg(REG_OFFSET_BG1VOFS, gBattle_BG1_Y); SetGpuReg(REG_OFFSET_BG2HOFS, gBattle_BG2_X); SetGpuReg(REG_OFFSET_BG2VOFS, gBattle_BG2_Y); LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); } #define SET_WIN0H_WIN1H(win0H, win1H) \ { \ *(vu32*)(REG_ADDR_WIN0H) = ((win0H << 16) | (win1H)); \ } static void HblankCb_TourneyTree(void) { u16 vCount = REG_VCOUNT; if (vCount < 42) { REG_WININ = WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_CLR | WININ_WIN1_OBJ; SET_WIN0H_WIN1H(0, 0); } else if (vCount < 50) { REG_WININ = WININ_WIN0_BG0 | WININ_WIN0_BG1 | WININ_WIN0_BG3 | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG0 | WININ_WIN1_BG1 | WININ_WIN1_BG3 | WININ_WIN1_OBJ | WININ_WIN1_CLR; SET_WIN0H_WIN1H(WIN_RANGE(152, 155), WIN_RANGE(85, 88)); } else if (vCount < 58) { REG_WININ = WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_CLR | WININ_WIN1_OBJ; SET_WIN0H_WIN1H(0, 0); } else if (vCount < 75) { REG_WININ = WININ_WIN0_BG0 | WININ_WIN0_BG1 | WININ_WIN0_BG3 | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG0 | WININ_WIN1_BG1 | WININ_WIN1_BG3 | WININ_WIN1_OBJ | WININ_WIN1_CLR; SET_WIN0H_WIN1H(WIN_RANGE(144, 152), WIN_RANGE(88, 96)); } else if (vCount < 82) { REG_WININ = WININ_WIN0_BG0 | WININ_WIN0_BG1 | WININ_WIN0_BG3 | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG0 | WININ_WIN1_BG1 | WININ_WIN1_BG3 | WININ_WIN1_OBJ | WININ_WIN1_CLR; SET_WIN0H_WIN1H(WIN_RANGE(152, 155), WIN_RANGE(85, 88)); } else if (vCount < 95) { REG_WININ = WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_CLR | WININ_WIN1_OBJ; SET_WIN0H_WIN1H(0, 0); } else if (vCount < 103) { REG_WININ = WININ_WIN0_BG0 | WININ_WIN0_BG1 | WININ_WIN0_BG2 | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG0 | WININ_WIN1_BG1 | WININ_WIN1_BG2 | WININ_WIN1_OBJ | WININ_WIN1_CLR; SET_WIN0H_WIN1H(WIN_RANGE(152, 155), WIN_RANGE(85, 88)); } else if (vCount < 119) { REG_WININ = WININ_WIN0_BG0 | WININ_WIN0_BG1 | WININ_WIN0_BG2 | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG0 | WININ_WIN1_BG1 | WININ_WIN1_BG2 | WININ_WIN1_OBJ | WININ_WIN1_CLR; SET_WIN0H_WIN1H(WIN_RANGE(144, 152), WIN_RANGE(88, 96)); } else if (vCount < 127) { REG_WININ = WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_CLR | WININ_WIN1_OBJ; SET_WIN0H_WIN1H(0, 0); } else if (vCount < 135) { REG_WININ = WININ_WIN0_BG0 | WININ_WIN0_BG1 | WININ_WIN0_BG2 | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG0 | WININ_WIN1_BG1 | WININ_WIN1_BG2 | WININ_WIN1_OBJ | WININ_WIN1_CLR; SET_WIN0H_WIN1H(WIN_RANGE(152, 155), WIN_RANGE(85, 88)); } else { REG_WININ = WININ_WIN0_BG_ALL | WININ_WIN0_CLR | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_CLR | WININ_WIN1_OBJ; SET_WIN0H_WIN1H(0, 0); } } static void VblankCb_TourneyTree(void) { SetGpuReg(REG_OFFSET_BG0HOFS, gBattle_BG0_X); SetGpuReg(REG_OFFSET_BG0VOFS, gBattle_BG0_Y); SetGpuReg(REG_OFFSET_BG1HOFS, gBattle_BG1_X); SetGpuReg(REG_OFFSET_BG1VOFS, gBattle_BG1_Y); ChangeBgY(2, 0x80, BG_COORD_SUB); ChangeBgY(3, 0x80, BG_COORD_ADD); LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); ScanlineEffect_InitHBlankDmaTransfer(); } static void SetFacilityTrainerAndMonPtrs(void) { gFacilityTrainerMons = gBattleFrontierMons; gFacilityTrainers = gBattleFrontierTrainers; } static void ResetSketchedMoves(void) { int i, moveSlot; for (i = 0; i < DOME_BATTLE_PARTY_SIZE; i++) { int playerMonId = gSaveBlock2Ptr->frontier.selectedPartyMons[gSelectedOrderFromParty[i] - 1] - 1; int count; for (moveSlot = 0; moveSlot < MAX_MON_MOVES; moveSlot++) { count = 0; while (count < MAX_MON_MOVES) { if (GetMonData(&gSaveBlock1Ptr->playerParty[playerMonId], MON_DATA_MOVE1 + count, NULL) == GetMonData(&gPlayerParty[i], MON_DATA_MOVE1 + moveSlot, NULL)) break; count++; } if (count == MAX_MON_MOVES) SetMonMoveSlot(&gPlayerParty[i], MOVE_SKETCH, moveSlot); } gSaveBlock1Ptr->playerParty[playerMonId] = gPlayerParty[i]; } } static void RestoreDomePlayerPartyHeldItems(void) { int i; for (i = 0; i < DOME_BATTLE_PARTY_SIZE; i++) { int playerMonId = gSaveBlock2Ptr->frontier.selectedPartyMons[gSelectedOrderFromParty[i] - 1] - 1; u16 item = GetMonData(&gSaveBlock1Ptr->playerParty[playerMonId], MON_DATA_HELD_ITEM, NULL); SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &item); } } static void ReduceDomePlayerPartyToSelectedMons(void) { ReducePlayerPartyToSelectedMons(); } static void GetPlayerSeededBeforeOpponent(void) { // A higher tournament ID is a worse seed if (TrainerIdToTournamentId(gTrainerBattleOpponent_A) > TrainerIdToTournamentId(TRAINER_PLAYER)) gSpecialVar_Result = 1; else gSpecialVar_Result = 2; } static void BufferLastDomeWinnerName(void) { int i; SetFacilityTrainerAndMonPtrs(); for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { if (!DOME_TRAINERS[i].isEliminated) break; } CopyDomeTrainerName(gStringVar1, DOME_TRAINERS[i].trainerId); } // For showing the previous tourney results before the player has entered a challenge static void InitRandomTourneyTreeResults(void) { int i, j, k; int monLevel; int species[FRONTIER_PARTY_SIZE]; int monTypesBits; int trainerId; int monId; int zero1; int zero2; u8 lvlMode; u16 *statSums; int *statValues; u8 ivs = 0; species[0] = 0; species[1] = 0; species[2] = 0; if ((gSaveBlock2Ptr->frontier.domeLvlMode != -gSaveBlock2Ptr->frontier.domeBattleMode) && gSaveBlock2Ptr->frontier.challengeStatus != CHALLENGE_STATUS_SAVING) return; statSums = AllocZeroed(sizeof(u16) * DOME_TOURNAMENT_TRAINERS_COUNT); statValues = AllocZeroed(sizeof(int) * NUM_STATS); lvlMode = gSaveBlock2Ptr->frontier.lvlMode; gSaveBlock2Ptr->frontier.lvlMode = FRONTIER_LVL_50; zero1 = 0; zero2 = 0; gSaveBlock2Ptr->frontier.domeLvlMode = zero1 + 1; gSaveBlock2Ptr->frontier.domeBattleMode = zero2 + 1; for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { do { if (i < 5) trainerId = Random() % 10; else if (i < 15) trainerId = Random() % 20 + 10; else trainerId = Random() % 10 + 30; for (j = 0; j < i; j++) { if (DOME_TRAINERS[j].trainerId == trainerId) break; } } while (j != i); DOME_TRAINERS[i].trainerId = trainerId; for (j = 0; j < FRONTIER_PARTY_SIZE; j++) { do { monId = GetRandomFrontierMonFromSet(trainerId); for (k = 0; k < j; k++) { // Make sure the mon is valid. int alreadySelectedMonId = DOME_MONS[i][k]; if (alreadySelectedMonId == monId || species[0] == gFacilityTrainerMons[monId].species || species[1] == gFacilityTrainerMons[monId].species || gFacilityTrainerMons[alreadySelectedMonId].itemTableId == gFacilityTrainerMons[monId].itemTableId) break; } } while (k != j); DOME_MONS[i][j] = monId; species[j] = gFacilityTrainerMons[monId].species; } DOME_TRAINERS[i].isEliminated = FALSE; DOME_TRAINERS[i].eliminatedAt = 0; DOME_TRAINERS[i].forfeited = FALSE; } monLevel = 50; for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { monTypesBits = 0; statSums[i] = 0; ivs = GetDomeTrainerMonIvs(DOME_TRAINERS[i].trainerId); for (j = 0; j < FRONTIER_PARTY_SIZE; j++) { CalcDomeMonStats(gFacilityTrainerMons[DOME_MONS[i][j]].species, monLevel, ivs, gFacilityTrainerMons[DOME_MONS[i][j]].evSpread, gFacilityTrainerMons[DOME_MONS[i][j]].nature, statValues); statSums[i] += statValues[STAT_ATK]; statSums[i] += statValues[STAT_DEF]; statSums[i] += statValues[STAT_SPATK]; statSums[i] += statValues[STAT_SPDEF]; statSums[i] += statValues[STAT_SPEED]; statSums[i] += statValues[STAT_HP]; monTypesBits |= gBitTable[gBaseStats[gFacilityTrainerMons[DOME_MONS[i][j]].species].type1]; monTypesBits |= gBitTable[gBaseStats[gFacilityTrainerMons[DOME_MONS[i][j]].species].type2]; } // Because GF hates temporary vars, trainerId acts like monTypesCount here. for (trainerId = 0, j = 0; j < 32; j++) { if (monTypesBits & 1) trainerId++; monTypesBits >>= 1; } statSums[i] += (trainerId * monLevel) / 20; } for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT - 1; i++) { for (j = i + 1; j < DOME_TOURNAMENT_TRAINERS_COUNT; j++) { if (statSums[i] < statSums[j]) { SwapDomeTrainers(i, j, statSums); } else if (statSums[i] == statSums[j]) { if (DOME_TRAINERS[i].trainerId > DOME_TRAINERS[j].trainerId) SwapDomeTrainers(i, j, statSums); } } } Free(statSums); Free(statValues); for (i = 0; i < DOME_ROUNDS_COUNT; i++) DecideRoundWinners(i); gSaveBlock2Ptr->frontier.lvlMode = lvlMode; } static int TrainerIdToTournamentId(u16 trainerId) { int i; for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { if (DOME_TRAINERS[i].trainerId == trainerId) break; } return i; } // The same as the above one, but has global scope. int TrainerIdToDomeTournamentId(u16 trainerId) { int i; for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { if (DOME_TRAINERS[i].trainerId == trainerId) break; } return i; } static u8 GetOpposingNPCTournamentIdByRound(u8 tournamentId, u8 round) { u8 tournamentIds[2]; BufferDomeWinString(sTrainerAndRoundToLastMatchCardNum[sTournamentIdToPairedTrainerIds[tournamentId] / 2][round] - 16, tournamentIds); if (tournamentId == tournamentIds[0]) return tournamentIds[1]; else return tournamentIds[0]; } // Determines which trainers won in the NPC vs NPC battles static void DecideRoundWinners(u8 roundId) { int i; int moveSlot, monId1, monId2; int tournamentId1, tournamentId2; int species; int points1 = 0, points2 = 0; for (i = 0; i < DOME_TOURNAMENT_TRAINERS_COUNT; i++) { if (DOME_TRAINERS[i].isEliminated || DOME_TRAINERS[i].trainerId == TRAINER_PLAYER) continue; tournamentId1 = i; tournamentId2 = TournamentIdOfOpponent(roundId, DOME_TRAINERS[tournamentId1].trainerId); // Frontier Brain always wins, check tournamentId1. if (DOME_TRAINERS[tournamentId1].trainerId == TRAINER_FRONTIER_BRAIN && tournamentId2 != 0xFF) { DOME_TRAINERS[tournamentId2].isEliminated = TRUE; DOME_TRAINERS[tournamentId2].eliminatedAt = roundId; gSaveBlock2Ptr->frontier.domeWinningMoves[tournamentId2] = GetWinningMove(tournamentId1, tournamentId2, roundId); } // Frontier Brain always wins, check tournamentId2. else if (DOME_TRAINERS[tournamentId2].trainerId == TRAINER_FRONTIER_BRAIN && tournamentId1 != 0xFF) { DOME_TRAINERS[tournamentId1].isEliminated = TRUE; DOME_TRAINERS[tournamentId1].eliminatedAt = roundId; gSaveBlock2Ptr->frontier.domeWinningMoves[tournamentId1] = GetWinningMove(tournamentId2, tournamentId1, roundId); } // Decide which one of two trainers wins! else if (tournamentId2 != 0xFF) { // BUG: points1 and points2 are not cleared at the beginning of the loop resulting in not fair results. #ifdef BUGFIX points1 = 0; points2 = 0; #endif // Calculate points for both trainers. for (monId1 = 0; monId1 < FRONTIER_PARTY_SIZE; monId1++) { for (moveSlot = 0; moveSlot < MAX_MON_MOVES; moveSlot++) { for (monId2 = 0; monId2 < FRONTIER_PARTY_SIZE; monId2++) { points1 += GetTypeEffectivenessPoints(gFacilityTrainerMons[DOME_MONS[tournamentId1][monId1]].moves[moveSlot], gFacilityTrainerMons[DOME_MONS[tournamentId2][monId2]].species, 2); } } species = gFacilityTrainerMons[DOME_MONS[tournamentId1][monId1]].species; points1 += ( gBaseStats[species].baseHP + gBaseStats[species].baseAttack + gBaseStats[species].baseDefense + gBaseStats[species].baseSpeed + gBaseStats[species].baseSpAttack + gBaseStats[species].baseSpDefense) / 10; } // Random part of the formula. points1 += (Random() & 0x1F); // Favor trainers with higher id; points1 += tournamentId1; for (monId1 = 0; monId1 < FRONTIER_PARTY_SIZE; monId1++) { for (moveSlot = 0; moveSlot < MAX_MON_MOVES; moveSlot++) { for (monId2 = 0; monId2 < FRONTIER_PARTY_SIZE; monId2++) { points2 += GetTypeEffectivenessPoints(gFacilityTrainerMons[DOME_MONS[tournamentId2][monId1]].moves[moveSlot], gFacilityTrainerMons[DOME_MONS[tournamentId1][monId2]].species, 2); } } species = gFacilityTrainerMons[DOME_MONS[tournamentId2][monId1]].species; points2 += ( gBaseStats[species].baseHP + gBaseStats[species].baseAttack + gBaseStats[species].baseDefense + gBaseStats[species].baseSpeed + gBaseStats[species].baseSpAttack + gBaseStats[species].baseSpDefense) / 10; } // Random part of the formula. points2 += (Random() & 0x1F); // Favor trainers with higher id; points2 += tournamentId2; if (points1 > points2) { DOME_TRAINERS[tournamentId2].isEliminated = TRUE; DOME_TRAINERS[tournamentId2].eliminatedAt = roundId; gSaveBlock2Ptr->frontier.domeWinningMoves[tournamentId2] = GetWinningMove(tournamentId1, tournamentId2, roundId); } else if (points1 < points2) { DOME_TRAINERS[tournamentId1].isEliminated = TRUE; DOME_TRAINERS[tournamentId1].eliminatedAt = roundId; gSaveBlock2Ptr->frontier.domeWinningMoves[tournamentId1] = GetWinningMove(tournamentId2, tournamentId1, roundId); } // Points are the same, so we favor the one with the higher id. else if (tournamentId1 > tournamentId2) { DOME_TRAINERS[tournamentId2].isEliminated = TRUE; DOME_TRAINERS[tournamentId2].eliminatedAt = roundId; gSaveBlock2Ptr->frontier.domeWinningMoves[tournamentId2] = GetWinningMove(tournamentId1, tournamentId2, roundId); } else { DOME_TRAINERS[tournamentId1].isEliminated = TRUE; DOME_TRAINERS[tournamentId1].eliminatedAt = roundId; gSaveBlock2Ptr->frontier.domeWinningMoves[tournamentId1] = GetWinningMove(tournamentId2, tournamentId1, roundId); } } } } static void CopyDomeTrainerName(u8 *str, u16 trainerId) { int i = 0; SetFacilityPtrsGetLevel(); if (trainerId == TRAINER_FRONTIER_BRAIN) { CopyDomeBrainTrainerName(str); } else { if (trainerId == TRAINER_PLAYER) { for (i = 0; i < PLAYER_NAME_LENGTH; i++) str[i] = gSaveBlock2Ptr->playerName[i]; } else if (trainerId < FRONTIER_TRAINERS_COUNT) { for (i = 0; i < PLAYER_NAME_LENGTH; i++) str[i] = gFacilityTrainers[trainerId].trainerName[i]; } str[i] = EOS; } } static u8 GetDomeBrainTrainerPicId(void) { return gTrainers[TRAINER_TUCKER].trainerPic; } static u8 GetDomeBrainTrainerClass(void) { return gTrainers[TRAINER_TUCKER].trainerClass; } static void CopyDomeBrainTrainerName(u8 *str) { int i; for (i = 0; i < PLAYER_NAME_LENGTH; i++) str[i] = gTrainers[TRAINER_TUCKER].trainerName[i]; str[i] = EOS; }