From f980e6258d336fd434df8b8b207b9ca87a2ea66a Mon Sep 17 00:00:00 2001 From: cawtds Date: Sat, 11 May 2024 01:30:30 +0200 Subject: [PATCH 01/11] refactored trainers --- include/constants/battle_ai.h | 6 +- include/constants/global.h | 1 + include/constants/opponents.h | 4 +- include/constants/trainers.h | 6 + include/data.h | 178 +- include/pokemon.h | 1 + src/battle_ai_script_commands.c | 6 +- src/battle_main.c | 405 ++- src/battle_message.c | 76 +- src/battle_setup.c | 65 +- src/data.c | 2 +- src/data/battle_partners.h | 2 +- src/data/text/trainer_class_names.h | 109 - src/data/trainer_parties.h | 3848 ++++++++++----------------- src/data/trainers.h | 2978 ++++++++++----------- src/pokemon.c | 7 +- src/union_room.c | 2 +- 17 files changed, 3437 insertions(+), 4259 deletions(-) delete mode 100644 src/data/text/trainer_class_names.h diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index d23648f39..e6301d01b 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -34,9 +34,9 @@ #define MOVE_MOST_POWERFUL 2 // script's table id to bit -#define AI_SCRIPT_CHECK_BAD_MOVE (1 << 0) -#define AI_SCRIPT_CHECK_VIABILITY (1 << 1) -#define AI_SCRIPT_TRY_TO_FAINT (1 << 2) +#define AI_FLAG_CHECK_BAD_MOVE (1 << 0) +#define AI_FLAG_CHECK_VIABILITY (1 << 1) +#define AI_FLAG_TRY_TO_FAINT (1 << 2) #define AI_SCRIPT_SETUP_FIRST_TURN (1 << 3) #define AI_SCRIPT_RISKY (1 << 4) #define AI_SCRIPT_PREFER_STRONGEST_MOVE (1 << 5) diff --git a/include/constants/global.h b/include/constants/global.h index 19f0afa9d..328b19193 100644 --- a/include/constants/global.h +++ b/include/constants/global.h @@ -82,6 +82,7 @@ #define WONDER_NEWS_BODY_TEXT_LINES 10 #define TYPE_NAME_LENGTH 6 #define ABILITY_NAME_LENGTH ((B_EXPANDED_ABILITY_NAMES == TRUE) ? 16 : 12) +#define TRAINER_NAME_LENGTH 10 #define MAX_STAMP_CARD_STAMPS 7 diff --git a/include/constants/opponents.h b/include/constants/opponents.h index b5fcc3d56..679037d6b 100644 --- a/include/constants/opponents.h +++ b/include/constants/opponents.h @@ -1,6 +1,8 @@ #ifndef GUARD_CONSTANTS_OPPONENTS_H #define GUARD_CONSTANTS_OPPONENTS_H +#include "constants/battle_partner.h" + #define TRAINER_NONE 0 // Dummy trainers for all the RS trainer classes #define TRAINER_AQUA_LEADER 1 @@ -752,7 +754,7 @@ // only space for 25 additional trainers before trainer flag space overflows. // MAX_TRAINERS_COUNT can be increased but will take up additional saveblock space -#define NUM_TRAINERS 744 +#define TRAINERS_COUNT 744 #define MAX_TRAINERS_COUNT 769 #define TRAINER_PARTNER(partner) (MAX_TRAINERS_COUNT + partner) diff --git a/include/constants/trainers.h b/include/constants/trainers.h index 70e8b4bc7..0e3825b0f 100644 --- a/include/constants/trainers.h +++ b/include/constants/trainers.h @@ -288,6 +288,8 @@ #define TRAINER_CLASS_LADY 105 #define TRAINER_CLASS_PAINTER 106 +#define TRAINER_CLASS_COUNT 107 + #define FACILITY_CLASS_AQUA_LEADER_ARCHIE 0 #define FACILITY_CLASS_AQUA_GRUNT_M 1 #define FACILITY_CLASS_AQUA_GRUNT_F 2 @@ -441,6 +443,10 @@ #define F_TRAINER_FEMALE (1 << 7) +// Trainer party defines +#define TRAINER_MON_MALE 1 +#define TRAINER_MON_FEMALE 2 + // All trainer parties specify the IV, level, and species for each Pokémon in the // party. Some trainer parties also specify held items and custom moves for each // Pokémon. diff --git a/include/data.h b/include/data.h index 01cbb2741..ce53a3fde 100644 --- a/include/data.h +++ b/include/data.h @@ -18,6 +18,8 @@ struct MonCoords #define MON_COORDS_SIZE(width, height)(DIV_ROUND_UP(width, 8) << 4 | DIV_ROUND_UP(height, 8)) #define GET_MON_COORDS_WIDTH(size)((size >> 4) * 8) #define GET_MON_COORDS_HEIGHT(size)((size & 0xF) * 8) +#define TRAINER_PARTY_IVS(hp, atk, def, speed, spatk, spdef) (hp | (atk << 5) | (def << 10) | (speed << 15) | (spatk << 20) | (spdef << 25)) +#define TRAINER_PARTY_EVS(hp, atk, def, speed, spatk, spdef) ((const u8[6]){hp,atk,def,spatk,spdef,speed}) #define MAX_TRAINER_ITEMS 4 @@ -28,76 +30,51 @@ enum { BATTLER_AFFINE_RETURN, }; -struct TrainerMonNoItemDefaultMoves +struct TrainerMon { - u16 iv; - u8 lvl; - u16 species; -}; - -struct TrainerMonItemDefaultMoves -{ - u16 iv; - u8 lvl; + const u8 *nickname; + const u8 *ev; + u32 iv; + u16 moves[4]; u16 species; u16 heldItem; -}; - -struct TrainerMonNoItemCustomMoves -{ - u16 iv; + u16 ability; u8 lvl; - u16 species; - u16 moves[MAX_MON_MOVES]; + u8 ball; + u8 friendship; + u8 nature:5; + bool8 gender:2; + bool8 isShiny:1; + u8 dynamaxLevel:4; + bool8 gigantamaxFactor:1; + bool8 shouldDynamax:1; + bool8 shouldTerastal:1; }; -struct TrainerMonItemCustomMoves -{ - u16 iv; - u8 lvl; - u16 species; - u16 heldItem; - u16 moves[MAX_MON_MOVES]; -}; - -#define NO_ITEM_DEFAULT_MOVES(party) { .NoItemDefaultMoves = party }, .partySize = ARRAY_COUNT(party), .partyFlags = 0 -#define NO_ITEM_CUSTOM_MOVES(party) { .NoItemCustomMoves = party }, .partySize = ARRAY_COUNT(party), .partyFlags = F_TRAINER_PARTY_CUSTOM_MOVESET -#define ITEM_DEFAULT_MOVES(party) { .ItemDefaultMoves = party }, .partySize = ARRAY_COUNT(party), .partyFlags = F_TRAINER_PARTY_HELD_ITEM -#define ITEM_CUSTOM_MOVES(party) { .ItemCustomMoves = party }, .partySize = ARRAY_COUNT(party), .partyFlags = F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM - -union TrainerMonPtr -{ - const struct TrainerMonNoItemDefaultMoves *NoItemDefaultMoves; - const struct TrainerMonNoItemCustomMoves *NoItemCustomMoves; - const struct TrainerMonItemDefaultMoves *ItemDefaultMoves; - const struct TrainerMonItemCustomMoves *ItemCustomMoves; -}; +#define TRAINER_PARTY(partyArray) partyArray, .partySize = ARRAY_COUNT(partyArray) struct Trainer { - /*0x00*/ u8 partyFlags; - /*0x01*/ u8 trainerClass; - /*0x02*/ u8 encounterMusic_gender; // last bit is gender - /*0x03*/ u8 trainerPic; - /*0x04*/ u8 trainerName[12]; - /*0x10*/ u16 items[MAX_TRAINER_ITEMS]; - /*0x18*/ bool8 doubleBattle; - /*0x1C*/ u32 aiFlags; + /*0x00*/ u32 aiFlags; + /*0x04*/ const struct TrainerMon *party; + /*0x08*/ u16 items[MAX_TRAINER_ITEMS]; + /*0x10*/ u8 trainerClass; + /*0x11*/ u8 encounterMusic_gender; // last bit is gender + /*0x12*/ u8 trainerPic; + /*0x13*/ u8 trainerName[TRAINER_NAME_LENGTH + 1]; + /*0x1E*/ bool8 doubleBattle:1; + bool8 mugshotEnabled:1; + u8 startingStatus:6; // this trainer starts a battle with a given status. see include/constants/battle.h for values + /*0x1F*/ u8 mugshotColor; /*0x20*/ u8 partySize; - /*0x24*/ const union TrainerMonPtr party; }; -// extern const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1]; -// extern const u8 gMoveNames[][MOVE_NAME_LENGTH + 1]; - -extern const u8 gTrainerClassNames[][13]; - -static inline u16 SanitizeTrainerId(u16 trainerId) +struct TrainerClass { - if (trainerId >= NUM_TRAINERS) - return TRAINER_NONE; - return trainerId; -} + u8 name[13]; + u8 money; + u16 ball; +}; struct TypeInfo { @@ -116,12 +93,6 @@ struct TypeInfo //u16 arceusForm; }; -// extern const struct MonCoords gMonFrontPicCoords[]; -// extern const struct CompressedSpriteSheet gMonFrontPicTable[]; -// extern const struct MonCoords gMonBackPicCoords[]; -// extern const struct CompressedSpriteSheet gMonBackPicTable[]; -// extern const struct CompressedSpritePalette gMonPaletteTable[]; -// extern const struct CompressedSpritePalette gMonShinyPaletteTable[]; extern const union AnimCmd *const *const gTrainerFrontAnimsPtrTable[]; extern const struct MonCoords gTrainerFrontPicCoords[]; extern const struct CompressedSpriteSheet gTrainerFrontPicTable[]; @@ -155,16 +126,85 @@ extern const struct SpriteFrameImage gTrainerBackPicTable_RSMay[]; extern const union AnimCmd sAnim_GeneralFrame0[]; extern const struct Trainer gTrainers[]; +extern const struct Trainer gBattlePartners[]; + +extern const struct TrainerClass gTrainerClasses[TRAINER_CLASS_COUNT]; + + +static inline u16 SanitizeTrainerId(u16 trainerId) +{ + if (trainerId >= TRAINERS_COUNT) + return TRAINER_NONE; + return trainerId; +} + +static inline const struct Trainer *GetTrainerStructFromId(u16 trainerId) +{ + return &gTrainers[SanitizeTrainerId(trainerId)]; +} + +static inline const u8 GetTrainerClassFromId(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].trainerClass; +} + +static inline const u8 *GetTrainerClassNameFromId(u16 trainerId) +{ + if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) + return gTrainerClasses[gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass].name; + return gTrainerClasses[GetTrainerClassFromId(trainerId)].name; +} static inline const u8 *GetTrainerNameFromId(u16 trainerId) { - // if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) - // return gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName; + if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) + return gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName; return gTrainers[SanitizeTrainerId(trainerId)].trainerName; } -// static inline const struct TrainerMon *GetTrainerPartyFromId(u16 trainerId) -// { -// return gTrainers[SanitizeTrainerId(trainerId)].party; -// } + +static inline const u8 GetTrainerPicFromId(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].trainerPic; +} + +static inline const u8 GetTrainerStartingStatusFromId(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].startingStatus; +} + +static inline const bool32 IsTrainerDoubleBattle(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].doubleBattle; +} + +static inline const u8 GetTrainerPartySizeFromId(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].partySize; +} + +static inline const bool32 DoesTrainerHaveMugshot(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].mugshotEnabled; +} + +static inline const u8 GetTrainerMugshotColorFromId(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].mugshotColor; +} + +static inline const u16 *GetTrainerItemsFromId(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].items; +} + +static inline const struct TrainerMon *GetTrainerPartyFromId(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].party; +} + +static inline const bool32 GetTrainerAIFlagsFromId(u16 trainerId) +{ + return gTrainers[SanitizeTrainerId(trainerId)].aiFlags; +} #endif // GUARD_DATA_H diff --git a/include/pokemon.h b/include/pokemon.h index 6dcb44176..2d22724d2 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -750,6 +750,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov u8 GetItemEffectParamOffset(u32 battler, u16 itemId, u8 effectByte, u8 effectBit); // const u8 *Battle_PrintStatBoosterEffectMessage(u16 itemId); u8 GetNature(struct Pokemon *mon); +u8 GetNatureFromPersonality(u32 personality); u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 type, u16 evolutionItem, struct Pokemon *tradePartner); u16 NationalPokedexNumToSpecies(u16 nationalNum); u16 SpeciesToNationalPokedexNum(u16 species); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index d2fbf719b..96506425d 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -379,18 +379,18 @@ void BattleAI_SetupAIData(u32 battler) { if (gBattleTypeFlags & BATTLE_TYPE_WILD_SCRIPTED) { - AI_THINKING_STRUCT->aiFlags = AI_SCRIPT_CHECK_BAD_MOVE; + AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE; return; } else if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY_FRLG) { - AI_THINKING_STRUCT->aiFlags = (AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY); + AI_THINKING_STRUCT->aiFlags = (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); return; } } else { - AI_THINKING_STRUCT->aiFlags = (AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY); + AI_THINKING_STRUCT->aiFlags = (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); return; } AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags; diff --git a/src/battle_main.c b/src/battle_main.c index 444f914d3..681278221 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -66,7 +66,7 @@ static void HandleEndTurn_FinishBattle(void); static void CB2_InitBattleInternal(void); static void CB2_PreInitMultiBattle(void); static void CB2_HandleStartMultiBattle(void); -static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum); +static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 firstTrainer); static void CB2_HandleStartBattle(void); static void TryCorrectShedinjaLanguage(struct Pokemon *mon); static void BattleMainCB1(void); @@ -593,28 +593,124 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = */ }; +// extra args are money and ball +#define TRAINER_CLASS(trainerClass, trainerName, ...) \ + [TRAINER_CLASS_##trainerClass] = \ + { \ + .name = _(trainerName), \ + .money = DEFAULT(5, __VA_ARGS__), \ + .ball = DEFAULT_2(ITEM_POKE_BALL, __VA_ARGS__), \ + } -static const union AnimCmd sAnim_Unused[] = +const struct TrainerClass gTrainerClasses[TRAINER_CLASS_COUNT] = { - ANIMCMD_FRAME(0, 5), - ANIMCMD_JUMP(0), -}; - -static const union AnimCmd *const sAnims_Unused[] = -{ - sAnim_Unused, -}; - -static const union AffineAnimCmd sAffineAnim_Unused[] = -{ - AFFINEANIMCMD_FRAME(-0x10, 0x0, 0, 4), - AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 0x3C), - AFFINEANIMCMD_JUMP(1), -}; - -static const union AffineAnimCmd *const sAffineAnims_Unused[] = -{ - sAffineAnim_Unused, + TRAINER_CLASS(NONE, "{PKMN} TRAINER"), + TRAINER_CLASS(PKMN_TRAINER_UNUSED, "{PKMN} TRAINER"), + TRAINER_CLASS(AQUA_LEADER, "AQUA LEADER"), + TRAINER_CLASS(TEAM_AQUA, "TEAM AQUA"), + TRAINER_CLASS(RS_AROMA_LADY, "AROMA LADY"), + TRAINER_CLASS(RS_RUIN_MANIAC, "RUIN MANIAC"), + TRAINER_CLASS(INTERVIEWER, "INTERVIEWER"), + TRAINER_CLASS(RS_TUBER_F, "TUBER"), + TRAINER_CLASS(RS_TUBER_M, "TUBER"), + TRAINER_CLASS(RS_COOLTRAINER, "COOLTRAINER"), + TRAINER_CLASS(HEX_MANIAC, "HEX MANIAC"), + TRAINER_CLASS(RS_LADY, "LADY"), + TRAINER_CLASS(RS_BEAUTY, "BEAUTY"), + TRAINER_CLASS(RICH_BOY, "RICH BOY"), + TRAINER_CLASS(RS_POKEMANIAC, "POKéMANIAC"), + TRAINER_CLASS(RS_SWIMMER_M, "SWIMMER♂"), + TRAINER_CLASS(RS_BLACK_BELT, "BLACK BELT"), + TRAINER_CLASS(GUITARIST, "GUITARIST"), + TRAINER_CLASS(KINDLER, "KINDLER"), + TRAINER_CLASS(RS_CAMPER, "CAMPER"), + TRAINER_CLASS(BUG_MANIAC, "BUG MANIAC"), + TRAINER_CLASS(RS_PSYCHIC, "PSYCHIC"), + TRAINER_CLASS(RS_GENTLEMAN, "GENTLEMAN"), + TRAINER_CLASS(RS_ELITE_FOUR, "ELITE FOUR"), + TRAINER_CLASS(RS_LEADER, "LEADER"), + TRAINER_CLASS(SCHOOL_KID, "SCHOOL KID"), + TRAINER_CLASS(SR_AND_JR, "SR. AND JR."), + TRAINER_CLASS(POKEFAN, "POKéFAN"), + TRAINER_CLASS(EXPERT, "EXPERT"), + TRAINER_CLASS(RS_YOUNGSTER, "YOUNGSTER"), + TRAINER_CLASS(RS_CHAMPION, "CHAMPION"), + TRAINER_CLASS(RS_FISHERMAN, "FISHERMAN"), + TRAINER_CLASS(TRIATHLETE, "TRIATHLETE"), + TRAINER_CLASS(DRAGON_TAMER, "DRAGON TAMER"), + TRAINER_CLASS(RS_BIRD_KEEPER, "BIRD KEEPER"), + TRAINER_CLASS(NINJA_BOY, "NINJA BOY"), + TRAINER_CLASS(BATTLE_GIRL, "BATTLE GIRL"), + TRAINER_CLASS(PARASOL_LADY, "PARASOL LADY"), + TRAINER_CLASS(RS_SWIMMER_F, "SWIMMER♀"), + TRAINER_CLASS(RS_PICNICKER, "PICNICKER"), + TRAINER_CLASS(RS_TWINS, "TWINS"), + TRAINER_CLASS(RS_SAILOR, "SAILOR"), + TRAINER_CLASS(BOARDER, "BOARDER"), + TRAINER_CLASS(COLLECTOR, "COLLECTOR"), + TRAINER_CLASS(PKMN_TRAINER, "{PKMN} TRAINER"), + TRAINER_CLASS(RS_PKMN_BREEDER, "{PKMN} BREEDER"), + TRAINER_CLASS(RS_PKMN_RANGER, "{PKMN} RANGER"), + TRAINER_CLASS(MAGMA_LEADER, "MAGMA LEADER"), + TRAINER_CLASS(TEAM_MAGMA, "TEAM MAGMA"), + TRAINER_CLASS(RS_LASS, "LASS"), + TRAINER_CLASS(RS_BUG_CATCHER, "BUG CATCHER"), + TRAINER_CLASS(RS_HIKER, "HIKER"), + TRAINER_CLASS(RS_YOUNG_COUPLE, "YOUNG COUPLE"), + TRAINER_CLASS(OLD_COUPLE, "OLD COUPLE"), + TRAINER_CLASS(RS_SIS_AND_BRO, "SIS AND BRO"), + TRAINER_CLASS(AQUA_ADMIN, "AQUA ADMIN"), + TRAINER_CLASS(MAGMA_ADMIN, "MAGMA ADMIN"), + TRAINER_CLASS(YOUNGSTER, "YOUNGSTER"), + TRAINER_CLASS(BUG_CATCHER, "BUG CATCHER"), + TRAINER_CLASS(LASS, "LASS"), + TRAINER_CLASS(SAILOR, "SAILOR"), + TRAINER_CLASS(CAMPER, "CAMPER"), + TRAINER_CLASS(PICNICKER, "PICNICKER"), + TRAINER_CLASS(POKEMANIAC, "POKéMANIAC"), + TRAINER_CLASS(SUPER_NERD, "SUPER NERD"), + TRAINER_CLASS(HIKER, "HIKER"), + TRAINER_CLASS(BIKER, "BIKER"), + TRAINER_CLASS(BURGLAR, "BURGLAR"), + TRAINER_CLASS(ENGINEER, "ENGINEER"), + TRAINER_CLASS(FISHERMAN, "FISHERMAN"), + TRAINER_CLASS(SWIMMER_M, "SWIMMER♂"), + TRAINER_CLASS(CUE_BALL, "CUE BALL"), + TRAINER_CLASS(GAMER, "GAMER"), + TRAINER_CLASS(BEAUTY, "BEAUTY"), + TRAINER_CLASS(SWIMMER_F, "SWIMMER♀"), + TRAINER_CLASS(PSYCHIC, "PSYCHIC"), + TRAINER_CLASS(ROCKER, "ROCKER"), + TRAINER_CLASS(JUGGLER, "JUGGLER"), + TRAINER_CLASS(TAMER, "TAMER"), + TRAINER_CLASS(BIRD_KEEPER, "BIRD KEEPER"), + TRAINER_CLASS(BLACK_BELT, "BLACK BELT"), + TRAINER_CLASS(RIVAL_EARLY, "RIVAL"), + TRAINER_CLASS(SCIENTIST, "SCIENTIST"), + TRAINER_CLASS(BOSS, "BOSS"), + TRAINER_CLASS(LEADER, "LEADER"), + TRAINER_CLASS(TEAM_ROCKET, "TEAM ROCKET"), + TRAINER_CLASS(COOLTRAINER, "COOLTRAINER"), + TRAINER_CLASS(ELITE_FOUR, "ELITE FOUR"), + TRAINER_CLASS(GENTLEMAN, "GENTLEMAN"), + TRAINER_CLASS(RIVAL_LATE, "RIVAL"), + TRAINER_CLASS(CHAMPION, "CHAMPION"), + TRAINER_CLASS(CHANNELER, "CHANNELER"), + TRAINER_CLASS(TWINS, "TWINS"), + TRAINER_CLASS(COOL_COUPLE, "COOL COUPLE"), + TRAINER_CLASS(YOUNG_COUPLE, "YOUNG COUPLE"), + TRAINER_CLASS(CRUSH_KIN, "CRUSH KIN"), + TRAINER_CLASS(SIS_AND_BRO, "SIS AND BRO"), + TRAINER_CLASS(PKMN_PROF, "{PKMN} PROF."), + TRAINER_CLASS(PLAYER, "PLAYER"), + TRAINER_CLASS(CRUSH_GIRL, "CRUSH GIRL"), + TRAINER_CLASS(TUBER, "TUBER"), + TRAINER_CLASS(PKMN_BREEDER, "{PKMN} BREEDER"), + TRAINER_CLASS(PKMN_RANGER, "{PKMN} RANGER"), + TRAINER_CLASS(AROMA_LADY, "AROMA LADY"), + TRAINER_CLASS(RUIN_MANIAC, "RUIN MANIAC"), + TRAINER_CLASS(LADY, "LADY"), + TRAINER_CLASS(PAINTER, "PAINTER"), }; static const s8 sPlayerThrowXTranslation[] = { -32, -16, -16, -32, -32, 0, 0, 0 }; @@ -865,6 +961,13 @@ static void CB2_InitBattleInternal(void) gBattleTerrain = BattleSetup_GetTerrainId(); + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & (BATTLE_TYPE_BATTLE_TOWER + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_TRAINER_TOWER))) + { + gBattleTypeFlags |= (IsTrainerDoubleBattle(gTrainerBattleOpponent_A) ? BATTLE_TYPE_DOUBLE : 0); + } + InitBattleBgsVideo(); LoadBattleTextboxAndBackground(); ResetSpriteData(); @@ -881,7 +984,7 @@ static void CB2_InitBattleInternal(void) SetMainCallback2(CB2_HandleStartBattle); if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) { - CreateNPCTrainerParty(&gEnemyParty[0], gTrainerBattleOpponent_A); + CreateNPCTrainerParty(&gEnemyParty[0], gTrainerBattleOpponent_A, FALSE); SetWildMonHeldItem(); } @@ -1743,112 +1846,210 @@ static void SpriteCB_UnusedDebugSprite_Step(struct Sprite *sprite) } } -static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum) +static u32 Crc32B (const u8 *data, u32 size) { - u32 nameHash = 0; - u32 personalityValue; - u8 fixedIV; - s32 i, j; + s32 i, j; + u32 byte, crc, mask; - if (trainerNum == TRAINER_SECRET_BASE) - return 0; - - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER - && !(gBattleTypeFlags & (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_TOWER))) - { - ZeroEnemyPartyMons(); - for (i = 0; i < gTrainers[trainerNum].partySize; i++) + i = 0; + crc = 0xFFFFFFFF; + for (i = 0; i < size; ++i) + { + byte = data[i]; + crc = crc ^ byte; + for (j = 7; j >= 0; --j) { + mask = -(crc & 1); + crc = (crc >> 1) ^ (0xEDB88320 & mask); + } + } + return ~crc; +} - if (gTrainers[trainerNum].doubleBattle == TRUE) +static u32 GeneratePartyHash(const struct Trainer *trainer, u32 i) +{ + const u8 *buffer = (const u8 *) &trainer->party[i]; + u32 n = sizeof(*trainer->party); + return Crc32B(buffer, n); +} + +void ModifyPersonalityForNature(u32 *personality, u32 newNature) +{ + u32 nature = GetNatureFromPersonality(*personality); + s32 diff = abs((s32)nature - (s32)newNature); + s32 sign = (nature > newNature) ? 1 : -1; + if (diff > NUM_NATURES / 2) + { + diff = NUM_NATURES - diff; + sign *= -1; + } + *personality -= (diff * sign); +} + +u32 GeneratePersonalityForGender(u32 gender, u32 species) +{ + const struct SpeciesInfo *speciesInfo = &gSpeciesInfo[species]; + if (gender == MON_MALE) + return ((255 - speciesInfo->genderRatio) / 2) + speciesInfo->genderRatio; + else + return speciesInfo->genderRatio / 2; +} + +void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMon *partyEntry) +{ + bool32 noMoveSet = TRUE; + u32 j; + + for (j = 0; j < MAX_MON_MOVES; ++j) + { + if (partyEntry->moves[j] != MOVE_NONE) + noMoveSet = FALSE; + } + if (noMoveSet) + { + // TODO: Figure out a default strategy when moves are not set, to generate a good moveset + return; + } + + for (j = 0; j < MAX_MON_MOVES; ++j) + { + SetMonData(mon, MON_DATA_MOVE1 + j, &partyEntry->moves[j]); + SetMonData(mon, MON_DATA_PP1 + j, &gMovesInfo[partyEntry->moves[j]].pp); + } +} + +u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags) +{ + u32 personalityValue; + s32 i; + u8 monsCount; + if (battleTypeFlags & BATTLE_TYPE_TRAINER && !(battleTypeFlags & (BATTLE_TYPE_BATTLE_TOWER + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_TRAINER_TOWER))) + { + if (firstTrainer == TRUE) + ZeroEnemyPartyMons(); + + if (battleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (trainer->partySize > PARTY_SIZE / 2) + monsCount = PARTY_SIZE / 2; + else + monsCount = trainer->partySize; + } + else + { + monsCount = trainer->partySize; + } + + for (i = 0; i < monsCount; i++) + { + s32 ball = -1; + u32 personalityHash = GeneratePartyHash(trainer, i); + const struct TrainerMon *partyData = trainer->party; + u32 otIdType = OT_ID_RANDOM_NO_SHINY; + u32 fixedOtId = 0; + u32 ability = 0; + + if (trainer->doubleBattle == TRUE) personalityValue = 0x80; - else if (gTrainers[trainerNum].encounterMusic_gender & F_TRAINER_FEMALE) + else if (trainer->encounterMusic_gender & F_TRAINER_FEMALE) personalityValue = 0x78; // Use personality more likely to result in a female Pokémon else personalityValue = 0x88; // Use personality more likely to result in a male Pokémon - for (j = 0; gTrainers[trainerNum].trainerName[j] != EOS; j++) - nameHash += gTrainers[trainerNum].trainerName[j]; - - switch (gTrainers[trainerNum].partyFlags) + personalityValue += personalityHash << 8; + if (partyData[i].gender == TRAINER_MON_MALE) + personalityValue = (personalityValue & 0xFFFFFF00) | GeneratePersonalityForGender(MON_MALE, partyData[i].species); + else if (partyData[i].gender == TRAINER_MON_FEMALE) + personalityValue = (personalityValue & 0xFFFFFF00) | GeneratePersonalityForGender(MON_FEMALE, partyData[i].species); + ModifyPersonalityForNature(&personalityValue, partyData[i].nature); + if (partyData[i].isShiny) { - case 0: - { - const struct TrainerMonNoItemDefaultMoves *partyData = gTrainers[trainerNum].party.NoItemDefaultMoves; - - for (j = 0; gSpeciesInfo[partyData[i].species].speciesName[j] != EOS; j++) - nameHash += gSpeciesInfo[partyData[i].species].speciesName[j]; - - personalityValue += nameHash << 8; - fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255; - CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); - break; + otIdType = OT_ID_PRESET; + fixedOtId = HIHALF(personalityValue) ^ LOHALF(personalityValue); } - case F_TRAINER_PARTY_CUSTOM_MOVESET: + CreateMon(&party[i], partyData[i].species, partyData[i].lvl, 0, TRUE, personalityValue, otIdType, fixedOtId); + SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem); + + CustomTrainerPartyAssignMoves(&party[i], &partyData[i]); + SetMonData(&party[i], MON_DATA_IVS, &(partyData[i].iv)); + if (partyData[i].ev != NULL) { - const struct TrainerMonNoItemCustomMoves *partyData = gTrainers[trainerNum].party.NoItemCustomMoves; - - for (j = 0; gSpeciesInfo[partyData[i].species].speciesName[j] != EOS; j++) - nameHash += gSpeciesInfo[partyData[i].species].speciesName[j]; - - personalityValue += nameHash << 8; - fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255; - CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); - - for (j = 0; j < MAX_MON_MOVES; j++) + SetMonData(&party[i], MON_DATA_HP_EV, &(partyData[i].ev[0])); + SetMonData(&party[i], MON_DATA_ATK_EV, &(partyData[i].ev[1])); + SetMonData(&party[i], MON_DATA_DEF_EV, &(partyData[i].ev[2])); + SetMonData(&party[i], MON_DATA_SPATK_EV, &(partyData[i].ev[3])); + SetMonData(&party[i], MON_DATA_SPDEF_EV, &(partyData[i].ev[4])); + SetMonData(&party[i], MON_DATA_SPEED_EV, &(partyData[i].ev[5])); + } + if (partyData[i].ability != ABILITY_NONE) + { + const struct SpeciesInfo *speciesInfo = &gSpeciesInfo[partyData[i].species]; + u32 maxAbilities = ARRAY_COUNT(speciesInfo->abilities); + for (ability = 0; ability < maxAbilities; ++ability) { - SetMonData(&party[i], MON_DATA_MOVE1 + j, &partyData[i].moves[j]); - SetMonData(&party[i], MON_DATA_PP1 + j, &gMovesInfo[partyData[i].moves[j]].pp); + if (speciesInfo->abilities[ability] == partyData[i].ability) + break; } - break; + if (ability >= maxAbilities) + ability = 0; } - case F_TRAINER_PARTY_HELD_ITEM: + else if (B_TRAINER_MON_RANDOM_ABILITY) { - const struct TrainerMonItemDefaultMoves *partyData = gTrainers[trainerNum].party.ItemDefaultMoves; - - for (j = 0; gSpeciesInfo[partyData[i].species].speciesName[j] != EOS; j++) - nameHash += gSpeciesInfo[partyData[i].species].speciesName[j]; - - personalityValue += nameHash << 8; - fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255; - CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); - - SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem); - break; - } - case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: - { - const struct TrainerMonItemCustomMoves *partyData = gTrainers[trainerNum].party.ItemCustomMoves; - - for (j = 0; gSpeciesInfo[partyData[i].species].speciesName[j] != EOS; j++) - nameHash += gSpeciesInfo[partyData[i].species].speciesName[j]; - - personalityValue += nameHash << 8; - fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255; - CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0); - SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem); - - for (j = 0; j < MAX_MON_MOVES; j++) + const struct SpeciesInfo *speciesInfo = &gSpeciesInfo[partyData[i].species]; + ability = personalityHash % 3; + while (speciesInfo->abilities[ability] == ABILITY_NONE) { - SetMonData(&party[i], MON_DATA_MOVE1 + j, &partyData[i].moves[j]); - SetMonData(&party[i], MON_DATA_PP1 + j, &gMovesInfo[partyData[i].moves[j]].pp); + ability--; } - break; } + SetMonData(&party[i], MON_DATA_ABILITY_NUM, &ability); + SetMonData(&party[i], MON_DATA_FRIENDSHIP, &(partyData[i].friendship)); + if (partyData[i].ball != ITEM_NONE) + { + ball = partyData[i].ball; + SetMonData(&party[i], MON_DATA_POKEBALL, &ball); + } + if (partyData[i].nickname != NULL) + { + SetMonData(&party[i], MON_DATA_NICKNAME, partyData[i].nickname); + } + if (partyData[i].isShiny) + { + u32 data = TRUE; + SetMonData(&party[i], MON_DATA_IS_SHINY, &data); + } + if (partyData[i].dynamaxLevel > 0) + { + u32 data = partyData[i].dynamaxLevel; + SetMonData(&party[i], MON_DATA_DYNAMAX_LEVEL, &data); + } + if (partyData[i].gigantamaxFactor) + { + u32 data = partyData[i].gigantamaxFactor; + SetMonData(&party[i], MON_DATA_GIGANTAMAX_FACTOR, &data); + } + CalculateMonStats(&party[i]); + + if (B_TRAINER_CLASS_POKE_BALLS >= GEN_7 && ball == -1) + { + ball = gTrainerClasses[trainer->trainerClass].ball ?: ITEM_POKE_BALL; + SetMonData(&party[i], MON_DATA_POKEBALL, &ball); } } - - gBattleTypeFlags |= gTrainers[trainerNum].doubleBattle; } - return gTrainers[trainerNum].partySize; + return trainer->partySize; } -// Unused -static void HBlankCB_Battle(void) +static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 firstTrainer) { - if (REG_VCOUNT < DISPLAY_HEIGHT && REG_VCOUNT >= 111) - REG_BG0CNT = BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(24) | BGCNT_16COLOR | BGCNT_TXT256x512; + u8 retVal; + if (trainerNum == TRAINER_SECRET_BASE) + return 0; + retVal = CreateNPCTrainerPartyFromTrainer(party, GetTrainerStructFromId(trainerNum), firstTrainer, gBattleTypeFlags); + return retVal; } void VBlankCB_Battle(void) diff --git a/src/battle_message.c b/src/battle_message.c index f7d98c431..d96517291 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -2827,6 +2827,24 @@ static const u8 *BattleStringGetTrainerName(u8 *text, u8 multiplayerId, u8 battl return BattleStringGetOpponentName(text, multiplayerId, battler); } +static const u8 *BattleStringGetOpponentClassByTrainerId(u16 trainerId) +{ + const u8 *toCpy; + + if (trainerId == TRAINER_UNION_ROOM) + toCpy = gTrainerClasses[GetUnionRoomTrainerClass()].name; + else if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + toCpy = gTrainerClasses[GetBattleTowerTrainerClassNameId()].name; + else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER) + toCpy = gTrainerClasses[GetTrainerTowerOpponentClass()].name; + else if (gBattleTypeFlags & BATTLE_TYPE_EREADER_TRAINER) + toCpy = gTrainerClasses[GetEreaderTrainerClassId()].name; + else + toCpy = gTrainerClasses[GetTrainerClassFromId(trainerId)].name; + + return toCpy; +} + u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst) { u32 dstId = 0; // if they used dstId, why not use srcId as well? @@ -2876,18 +2894,14 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst) toCpy = gBattleTextBuff3; break; case B_TXT_TRAINER2_CLASS: - // TODO: trainer name - // toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_B); - toCpy = "TODO"; + toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_B); break; case B_TXT_TRAINER2_NAME: - // TODO: trainer name - // toCpy = BattleStringGetOpponentNameByTrainerId(gTrainerBattleOpponent_B, text, multiplayerId, GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)); - toCpy = "TODO"; + toCpy = BattleStringGetOpponentNameByTrainerId(gTrainerBattleOpponent_B, text, multiplayerId, GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)); break; case B_TXT_PARTNER_CLASS: // TODO: trainer name - // toCpy = gTrainerClassNames[GetFrontierOpponentClass(gPartnerTrainerId)].name; + // toCpy = gTrainerClasses[GetFrontierOpponentClass(gPartnerTrainerId)].name; toCpy = "TODO"; break; case B_TXT_PARTNER_NAME: @@ -3053,17 +3067,17 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst) break; case B_TXT_TRAINER1_CLASS: // trainer class name if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE) - toCpy = gTrainerClassNames[GetSecretBaseTrainerNameIndex()]; + toCpy = gTrainerClasses[GetSecretBaseTrainerNameIndex()].name; else if (gTrainerBattleOpponent_A == TRAINER_UNION_ROOM) - toCpy = gTrainerClassNames[GetUnionRoomTrainerClass()]; + toCpy = gTrainerClasses[GetUnionRoomTrainerClass()].name; else if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) - toCpy = gTrainerClassNames[GetBattleTowerTrainerClassNameId()]; + toCpy = gTrainerClasses[GetBattleTowerTrainerClassNameId()].name; else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER) - toCpy = gTrainerClassNames[GetTrainerTowerOpponentClass()]; + toCpy = gTrainerClasses[GetTrainerTowerOpponentClass()].name; else if (gBattleTypeFlags & BATTLE_TYPE_EREADER_TRAINER) - toCpy = gTrainerClassNames[GetEreaderTrainerClassId()]; + toCpy = gTrainerClasses[GetEreaderTrainerClassId()].name; else - toCpy = gTrainerClassNames[gTrainers[gTrainerBattleOpponent_A].trainerClass]; + toCpy = gTrainerClasses[gTrainers[gTrainerBattleOpponent_A].trainerClass].name; break; case B_TXT_TRAINER1_NAME: // trainer1 name if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE) @@ -3199,24 +3213,24 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst) toCpy = BattleStringGetTrainerName(text, multiplayerId, gBattlerAttacker); break; case B_TXT_ATK_TRAINER_CLASS: - // TODO: get trainer name - toCpy = "TODO"; - // switch (GetBattlerPosition(gBattlerAttacker)) - // { - // case B_POSITION_PLAYER_RIGHT: - // if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) - // toCpy = gTrainerClasses[GetFrontierOpponentClass(gPartnerTrainerId)].name; - // break; - // case B_POSITION_OPPONENT_LEFT: - // toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A); - // break; - // case B_POSITION_OPPONENT_RIGHT: - // if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && !BATTLE_TWO_VS_ONE_OPPONENT) - // toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_B); - // else - // toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A); - // break; - // } + switch (GetBattlerPosition(gBattlerAttacker)) + { + case B_POSITION_PLAYER_RIGHT: + // TODO: implement partner trainers? + // if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + // toCpy = gTrainerClasses[GetFrontierOpponentClass(gPartnerTrainerId)].name; + toCpy = gTrainerClasses[TRAINER_CLASS_NONE].name; + break; + case B_POSITION_OPPONENT_LEFT: + toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A); + break; + case B_POSITION_OPPONENT_RIGHT: + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && !BATTLE_TWO_VS_ONE_OPPONENT) + toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_B); + else + toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A); + break; + } break; case B_TXT_ATK_TEAM1: if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) diff --git a/src/battle_setup.c b/src/battle_setup.c index 16b593ff3..9093f5346 100644 --- a/src/battle_setup.c +++ b/src/battle_setup.c @@ -564,49 +564,17 @@ static u8 GetSumOfEnemyPartyLevel(u16 opponentId, u8 numMons) u8 i; u8 sum; u32 count = numMons; + const struct TrainerMon *party; + + if (GetTrainerPartySizeFromId(opponentId) < count) + count = GetTrainerPartySizeFromId(opponentId); - if (gTrainers[opponentId].partySize < count) - count = gTrainers[opponentId].partySize; sum = 0; - switch (gTrainers[opponentId].partyFlags) - { - case 0: - { - const struct TrainerMonNoItemDefaultMoves *party; - party = gTrainers[opponentId].party.NoItemDefaultMoves; - for (i = 0; i < count; ++i) - sum += party[i].lvl; - } - break; - case F_TRAINER_PARTY_CUSTOM_MOVESET: - { - const struct TrainerMonNoItemCustomMoves *party; + party = GetTrainerPartyFromId(opponentId); + for (i = 0; i < count && party != NULL; i++) + sum += party[i].lvl; - party = gTrainers[opponentId].party.NoItemCustomMoves; - for (i = 0; i < count; ++i) - sum += party[i].lvl; - } - break; - case F_TRAINER_PARTY_HELD_ITEM: - { - const struct TrainerMonItemDefaultMoves *party; - - party = gTrainers[opponentId].party.ItemDefaultMoves; - for (i = 0; i < count; ++i) - sum += party[i].lvl; - } - break; - case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM: - { - const struct TrainerMonItemCustomMoves *party; - - party = gTrainers[opponentId].party.ItemCustomMoves; - for (i = 0; i < count; ++i) - sum += party[i].lvl; - } - break; - } return sum; } @@ -628,29 +596,30 @@ static u8 GetTrainerBattleTransition(void) u8 transitionType; u8 enemyLevel; u8 playerLevel; + u32 trainerId = SanitizeTrainerId(gTrainerBattleOpponent_A); - if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE) + if (trainerId == TRAINER_SECRET_BASE) return B_TRANSITION_BLUE; - if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_ELITE_FOUR) + if (gTrainers[trainerId].trainerClass == TRAINER_CLASS_ELITE_FOUR) { - if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LORELEI || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LORELEI_2) + if (trainerId == TRAINER_ELITE_FOUR_LORELEI || trainerId == TRAINER_ELITE_FOUR_LORELEI_2) return B_TRANSITION_LORELEI; - if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_BRUNO || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_BRUNO_2) + if (trainerId == TRAINER_ELITE_FOUR_BRUNO || trainerId == TRAINER_ELITE_FOUR_BRUNO_2) return B_TRANSITION_BRUNO; - if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_AGATHA || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_AGATHA_2) + if (trainerId == TRAINER_ELITE_FOUR_AGATHA || trainerId == TRAINER_ELITE_FOUR_AGATHA_2) return B_TRANSITION_AGATHA; - if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LANCE || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LANCE_2) + if (trainerId == TRAINER_ELITE_FOUR_LANCE || trainerId == TRAINER_ELITE_FOUR_LANCE_2) return B_TRANSITION_LANCE; return B_TRANSITION_BLUE; } - if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_CHAMPION) + if (gTrainers[trainerId].trainerClass == TRAINER_CLASS_CHAMPION) return B_TRANSITION_BLUE; - if (gTrainers[gTrainerBattleOpponent_A].doubleBattle == TRUE) + if (gTrainers[trainerId].doubleBattle == TRUE) minPartyCount = 2; // double battles always at least have 2 pokemon. else minPartyCount = 1; transitionType = GetBattleTransitionTypeByMap(); - enemyLevel = GetSumOfEnemyPartyLevel(gTrainerBattleOpponent_A, minPartyCount); + enemyLevel = GetSumOfEnemyPartyLevel(trainerId, minPartyCount); playerLevel = GetSumOfPlayerPartyLevel(minPartyCount); if (enemyLevel < playerLevel) return sBattleTransitionTable_Trainer[transitionType][0]; diff --git a/src/data.c b/src/data.c index c5489ffd9..f727b57db 100644 --- a/src/data.c +++ b/src/data.c @@ -290,5 +290,5 @@ const union AnimCmd *const gAnims_MonPic[] = #include "data/trainer_graphics/back_pic_tables.h" #include "data/trainer_parties.h" -#include "data/text/trainer_class_names.h" #include "data/trainers.h" +#include "data/battle_partners.h" diff --git a/src/data/battle_partners.h b/src/data/battle_partners.h index f64af2c88..fa2c6cc40 100644 --- a/src/data/battle_partners.h +++ b/src/data/battle_partners.h @@ -2,7 +2,7 @@ const struct Trainer gBattlePartners[] = { [PARTNER_NONE] = { .party = NULL, - .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, + .trainerClass = TRAINER_CLASS_NONE, .encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE, .trainerPic = TRAINER_PIC_HIKER, .trainerName = _(""), diff --git a/src/data/text/trainer_class_names.h b/src/data/text/trainer_class_names.h deleted file mode 100644 index cedb48b89..000000000 --- a/src/data/text/trainer_class_names.h +++ /dev/null @@ -1,109 +0,0 @@ -const u8 gTrainerClassNames[][13] = { - [TRAINER_CLASS_NONE] = _("{PKMN} TRAINER"), - [TRAINER_CLASS_PKMN_TRAINER_UNUSED] = _("{PKMN} TRAINER"), - [TRAINER_CLASS_AQUA_LEADER] = _("AQUA LEADER"), - [TRAINER_CLASS_TEAM_AQUA] = _("TEAM AQUA"), - [TRAINER_CLASS_RS_AROMA_LADY] = _("AROMA LADY"), - [TRAINER_CLASS_RS_RUIN_MANIAC] = _("RUIN MANIAC"), - [TRAINER_CLASS_INTERVIEWER] = _("INTERVIEWER"), - [TRAINER_CLASS_RS_TUBER_F] = _("TUBER"), - [TRAINER_CLASS_RS_TUBER_M] = _("TUBER"), - [TRAINER_CLASS_RS_COOLTRAINER] = _("COOLTRAINER"), - [TRAINER_CLASS_HEX_MANIAC] = _("HEX MANIAC"), - [TRAINER_CLASS_RS_LADY] = _("LADY"), - [TRAINER_CLASS_RS_BEAUTY] = _("BEAUTY"), - [TRAINER_CLASS_RICH_BOY] = _("RICH BOY"), - [TRAINER_CLASS_RS_POKEMANIAC] = _("POKéMANIAC"), - [TRAINER_CLASS_RS_SWIMMER_M] = _("SWIMMER♂"), - [TRAINER_CLASS_RS_BLACK_BELT] = _("BLACK BELT"), - [TRAINER_CLASS_GUITARIST] = _("GUITARIST"), - [TRAINER_CLASS_KINDLER] = _("KINDLER"), - [TRAINER_CLASS_RS_CAMPER] = _("CAMPER"), - [TRAINER_CLASS_BUG_MANIAC] = _("BUG MANIAC"), - [TRAINER_CLASS_RS_PSYCHIC] = _("PSYCHIC"), - [TRAINER_CLASS_RS_GENTLEMAN] = _("GENTLEMAN"), - [TRAINER_CLASS_RS_ELITE_FOUR] = _("ELITE FOUR"), - [TRAINER_CLASS_RS_LEADER] = _("LEADER"), - [TRAINER_CLASS_SCHOOL_KID] = _("SCHOOL KID"), - [TRAINER_CLASS_SR_AND_JR] = _("SR. AND JR."), - [TRAINER_CLASS_POKEFAN] = _("POKéFAN"), - [TRAINER_CLASS_EXPERT] = _("EXPERT"), - [TRAINER_CLASS_RS_YOUNGSTER] = _("YOUNGSTER"), - [TRAINER_CLASS_RS_CHAMPION] = _("CHAMPION"), - [TRAINER_CLASS_RS_FISHERMAN] = _("FISHERMAN"), - [TRAINER_CLASS_TRIATHLETE] = _("TRIATHLETE"), - [TRAINER_CLASS_DRAGON_TAMER] = _("DRAGON TAMER"), - [TRAINER_CLASS_RS_BIRD_KEEPER] = _("BIRD KEEPER"), - [TRAINER_CLASS_NINJA_BOY] = _("NINJA BOY"), - [TRAINER_CLASS_BATTLE_GIRL] = _("BATTLE GIRL"), - [TRAINER_CLASS_PARASOL_LADY] = _("PARASOL LADY"), - [TRAINER_CLASS_RS_SWIMMER_F] = _("SWIMMER♀"), - [TRAINER_CLASS_RS_PICNICKER] = _("PICNICKER"), - [TRAINER_CLASS_RS_TWINS] = _("TWINS"), - [TRAINER_CLASS_RS_SAILOR] = _("SAILOR"), - [TRAINER_CLASS_BOARDER] = _("BOARDER"), - [TRAINER_CLASS_COLLECTOR] = _("COLLECTOR"), - [TRAINER_CLASS_PKMN_TRAINER] = _("{PKMN} TRAINER"), - [TRAINER_CLASS_RS_PKMN_BREEDER] = _("{PKMN} BREEDER"), - [TRAINER_CLASS_RS_PKMN_RANGER] = _("{PKMN} RANGER"), - [TRAINER_CLASS_MAGMA_LEADER] = _("MAGMA LEADER"), - [TRAINER_CLASS_TEAM_MAGMA] = _("TEAM MAGMA"), - [TRAINER_CLASS_RS_LASS] = _("LASS"), - [TRAINER_CLASS_RS_BUG_CATCHER] = _("BUG CATCHER"), - [TRAINER_CLASS_RS_HIKER] = _("HIKER"), - [TRAINER_CLASS_RS_YOUNG_COUPLE] = _("YOUNG COUPLE"), - [TRAINER_CLASS_OLD_COUPLE] = _("OLD COUPLE"), - [TRAINER_CLASS_RS_SIS_AND_BRO] = _("SIS AND BRO"), - [TRAINER_CLASS_AQUA_ADMIN] = _("AQUA ADMIN"), - [TRAINER_CLASS_MAGMA_ADMIN] = _("MAGMA ADMIN"), - [TRAINER_CLASS_YOUNGSTER] = _("YOUNGSTER"), - [TRAINER_CLASS_BUG_CATCHER] = _("BUG CATCHER"), - [TRAINER_CLASS_LASS] = _("LASS"), - [TRAINER_CLASS_SAILOR] = _("SAILOR"), - [TRAINER_CLASS_CAMPER] = _("CAMPER"), - [TRAINER_CLASS_PICNICKER] = _("PICNICKER"), - [TRAINER_CLASS_POKEMANIAC] = _("POKéMANIAC"), - [TRAINER_CLASS_SUPER_NERD] = _("SUPER NERD"), - [TRAINER_CLASS_HIKER] = _("HIKER"), - [TRAINER_CLASS_BIKER] = _("BIKER"), - [TRAINER_CLASS_BURGLAR] = _("BURGLAR"), - [TRAINER_CLASS_ENGINEER] = _("ENGINEER"), - [TRAINER_CLASS_FISHERMAN] = _("FISHERMAN"), - [TRAINER_CLASS_SWIMMER_M] = _("SWIMMER♂"), - [TRAINER_CLASS_CUE_BALL] = _("CUE BALL"), - [TRAINER_CLASS_GAMER] = _("GAMER"), - [TRAINER_CLASS_BEAUTY] = _("BEAUTY"), - [TRAINER_CLASS_SWIMMER_F] = _("SWIMMER♀"), - [TRAINER_CLASS_PSYCHIC] = _("PSYCHIC"), - [TRAINER_CLASS_ROCKER] = _("ROCKER"), - [TRAINER_CLASS_JUGGLER] = _("JUGGLER"), - [TRAINER_CLASS_TAMER] = _("TAMER"), - [TRAINER_CLASS_BIRD_KEEPER] = _("BIRD KEEPER"), - [TRAINER_CLASS_BLACK_BELT] = _("BLACK BELT"), - [TRAINER_CLASS_RIVAL_EARLY] = _("RIVAL"), - [TRAINER_CLASS_SCIENTIST] = _("SCIENTIST"), - [TRAINER_CLASS_BOSS] = _("BOSS"), - [TRAINER_CLASS_LEADER] = _("LEADER"), - [TRAINER_CLASS_TEAM_ROCKET] = _("TEAM ROCKET"), - [TRAINER_CLASS_COOLTRAINER] = _("COOLTRAINER"), - [TRAINER_CLASS_ELITE_FOUR] = _("ELITE FOUR"), - [TRAINER_CLASS_GENTLEMAN] = _("GENTLEMAN"), - [TRAINER_CLASS_RIVAL_LATE] = _("RIVAL"), - [TRAINER_CLASS_CHAMPION] = _("CHAMPION"), - [TRAINER_CLASS_CHANNELER] = _("CHANNELER"), - [TRAINER_CLASS_TWINS] = _("TWINS"), - [TRAINER_CLASS_COOL_COUPLE] = _("COOL COUPLE"), - [TRAINER_CLASS_YOUNG_COUPLE] = _("YOUNG COUPLE"), - [TRAINER_CLASS_CRUSH_KIN] = _("CRUSH KIN"), - [TRAINER_CLASS_SIS_AND_BRO] = _("SIS AND BRO"), - [TRAINER_CLASS_PKMN_PROF] = _("{PKMN} PROF."), - [TRAINER_CLASS_PLAYER] = _("PLAYER"), - [TRAINER_CLASS_CRUSH_GIRL] = _("CRUSH GIRL"), - [TRAINER_CLASS_TUBER] = _("TUBER"), - [TRAINER_CLASS_PKMN_BREEDER] = _("{PKMN} BREEDER"), - [TRAINER_CLASS_PKMN_RANGER] = _("{PKMN} RANGER"), - [TRAINER_CLASS_AROMA_LADY] = _("AROMA LADY"), - [TRAINER_CLASS_RUIN_MANIAC] = _("RUIN MANIAC"), - [TRAINER_CLASS_LADY] = _("LADY"), - [TRAINER_CLASS_PAINTER] = _("PAINTER"), -}; diff --git a/src/data/trainer_parties.h b/src/data/trainer_parties.h index e9faf0af1..275a02365 100644 --- a/src/data/trainer_parties.h +++ b/src/data/trainer_parties.h @@ -9,7 +9,7 @@ #define DUMMY_TRAINER_MON_IV \ { \ - .iv = 100, \ + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), \ .lvl = 5, \ .species = SPECIES_EKANS, \ } @@ -21,5465 +21,4813 @@ .species = SPECIES_STARMIE, \ } -static const struct TrainerMonNoItemDefaultMoves sParty_AquaLeader[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_AquaGruntM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_AquaGruntF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSAromaLady[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSRuinManiac[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_Interviewer[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSTuberF[] = {DUMMY_TRAINER_STARMIE}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSTuberM[] = {DUMMY_TRAINER_STARMIE}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSCooltrainerM[] = {DUMMY_TRAINER_MON_IV}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSCooltrainerF[] = {DUMMY_TRAINER_MON_IV}; -static const struct TrainerMonNoItemDefaultMoves sParty_HexManiac[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSLady[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSBeauty[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RichBoy[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSPokemaniac[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSSwimmerM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSBlackBelt[] = {DUMMY_TRAINER_MON_IV}; -static const struct TrainerMonNoItemDefaultMoves sParty_Guitarist[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_Kindler[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSCamper[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BugManiac[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSPsychicM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSPsychicF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSGentleman[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_EliteFourSidney[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_EliteFourPhoebe[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_LeaderRoxanne[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_LeaderBrawly[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_LeaderTateLiza[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_SchoolKidM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_SchoolKidF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_SrAndJr[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_PokefanM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_PokefanF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_ExpertM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_ExpertF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSYoungster[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSChampion[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSFisherman[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_CyclingTriathleteM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_CyclingTriathleteF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RunningTriathleteM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RunningTriathleteF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmingTriathleteM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmingTriathleteF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_DragonTamer[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSBirdKeeper[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_NinjaBoy[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BattleGirl[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_ParasolLady[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSSwimmerF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSPicnicker[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSTwins[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSSailor[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BoarderM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BoarderF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_Collector[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_Wally[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_Brendan[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_Brendan2[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_Brendan3[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_May[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_May2[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_May3[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSPkmnBreederM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSPkmnBreederF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSPkmnRangerM[] = {DUMMY_TRAINER_MON_IV}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSPkmnRangerF[] = {DUMMY_TRAINER_MON_IV}; -static const struct TrainerMonNoItemDefaultMoves sParty_MagmaLeader[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_MagmaGruntM[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_MagmaGruntF[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSLass[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSBugCatcher[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSHiker[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSYoungCouple[] = {DUMMY_TRAINER_MON, DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_OldCouple[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_RSSisAndBro[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_AquaAdminMatt[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_AquaAdminShelly[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_MagmaAdminTabitha[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_MagmaAdminCourtney[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_LeaderWattson[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_LeaderFlannery[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_LeaderNorman[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_LeaderWinona[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_LeaderWallace[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_EliteFourGlacia[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_EliteFourDrake[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_AquaLeader[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_AquaGruntM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_AquaGruntF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSAromaLady[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSRuinManiac[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Interviewer[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSTuberF[] = {DUMMY_TRAINER_STARMIE}; +static const struct TrainerMon sParty_RSTuberM[] = {DUMMY_TRAINER_STARMIE}; +static const struct TrainerMon sParty_RSCooltrainerM[] = {DUMMY_TRAINER_MON_IV}; +static const struct TrainerMon sParty_RSCooltrainerF[] = {DUMMY_TRAINER_MON_IV}; +static const struct TrainerMon sParty_HexManiac[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSLady[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSBeauty[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RichBoy[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSPokemaniac[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSSwimmerM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSBlackBelt[] = {DUMMY_TRAINER_MON_IV}; +static const struct TrainerMon sParty_Guitarist[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Kindler[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSCamper[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BugManiac[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSPsychicM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSPsychicF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSGentleman[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_EliteFourSidney[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_EliteFourPhoebe[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_LeaderRoxanne[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_LeaderBrawly[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_LeaderTateLiza[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_SchoolKidM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_SchoolKidF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_SrAndJr[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_PokefanM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_PokefanF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_ExpertM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_ExpertF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSYoungster[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSChampion[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSFisherman[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_CyclingTriathleteM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_CyclingTriathleteF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RunningTriathleteM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RunningTriathleteF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_SwimmingTriathleteM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_SwimmingTriathleteF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_DragonTamer[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSBirdKeeper[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_NinjaBoy[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BattleGirl[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_ParasolLady[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSSwimmerF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSPicnicker[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSTwins[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSSailor[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BoarderM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BoarderF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Collector[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Wally[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Brendan[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Brendan2[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Brendan3[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_May[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_May2[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_May3[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSPkmnBreederM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSPkmnBreederF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSPkmnRangerM[] = {DUMMY_TRAINER_MON_IV}; +static const struct TrainerMon sParty_RSPkmnRangerF[] = {DUMMY_TRAINER_MON_IV}; +static const struct TrainerMon sParty_MagmaLeader[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_MagmaGruntM[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_MagmaGruntF[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSLass[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSBugCatcher[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSHiker[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSYoungCouple[] = {DUMMY_TRAINER_MON, DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_OldCouple[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_RSSisAndBro[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_AquaAdminMatt[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_AquaAdminShelly[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_MagmaAdminTabitha[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_MagmaAdminCourtney[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_LeaderWattson[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_LeaderFlannery[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_LeaderNorman[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_LeaderWinona[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_LeaderWallace[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_EliteFourGlacia[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_EliteFourDrake[] = {DUMMY_TRAINER_MON}; // Start of actual trainer data -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterBen[] = { +static const struct TrainerMon sParty_YoungsterBen[] = { { - .iv = 0, .lvl = 11, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 11, .species = SPECIES_EKANS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterCalvin[] = { +static const struct TrainerMon sParty_YoungsterCalvin[] = { { - .iv = 0, .lvl = 14, .species = SPECIES_SPEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterJosh[] = { +static const struct TrainerMon sParty_YoungsterJosh[] = { { - .iv = 0, .lvl = 10, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 10, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 10, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterTimmy[] = { +static const struct TrainerMon sParty_YoungsterTimmy[] = { { - .iv = 0, .lvl = 14, .species = SPECIES_SANDSHREW, }, { - .iv = 0, .lvl = 14, .species = SPECIES_EKANS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterJoey[] = { +static const struct TrainerMon sParty_YoungsterJoey[] = { { - .iv = 0, .lvl = 15, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 15, .species = SPECIES_SPEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterDan[] = { +static const struct TrainerMon sParty_YoungsterDan[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_SLOWPOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterChad[] = { +static const struct TrainerMon sParty_YoungsterChad[] = { { - .iv = 0, .lvl = 14, .species = SPECIES_EKANS, }, { - .iv = 0, .lvl = 14, .species = SPECIES_SANDSHREW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterTyler[] = { +static const struct TrainerMon sParty_YoungsterTyler[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_NIDORAN_M, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterEddie[] = { +static const struct TrainerMon sParty_YoungsterEddie[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_EKANS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterDillon[] = { +static const struct TrainerMon sParty_YoungsterDillon[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_SANDSHREW, }, { - .iv = 0, .lvl = 19, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterYasu[] = { +static const struct TrainerMon sParty_YoungsterYasu[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 17, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 17, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterDave[] = { +static const struct TrainerMon sParty_YoungsterDave[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_NIDORAN_M, }, { - .iv = 0, .lvl = 18, .species = SPECIES_NIDORINO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterBen2[] = { +static const struct TrainerMon sParty_YoungsterBen2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 17, .species = SPECIES_RATTATA, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 17, .species = SPECIES_EKANS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherRick[] = { +static const struct TrainerMon sParty_BugCatcherRick[] = { { - .iv = 0, .lvl = 6, .species = SPECIES_WEEDLE, }, { - .iv = 0, .lvl = 6, .species = SPECIES_CATERPIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherDoug[] = { +static const struct TrainerMon sParty_BugCatcherDoug[] = { { - .iv = 0, .lvl = 7, .species = SPECIES_WEEDLE, }, { - .iv = 0, .lvl = 7, .species = SPECIES_KAKUNA, }, { - .iv = 0, .lvl = 7, .species = SPECIES_WEEDLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherSammy[] = { +static const struct TrainerMon sParty_BugCatcherSammy[] = { { - .iv = 0, .lvl = 9, .species = SPECIES_WEEDLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherColton[] = { +static const struct TrainerMon sParty_BugCatcherColton[] = { { - .iv = 0, .lvl = 10, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 10, .species = SPECIES_WEEDLE, }, { - .iv = 0, .lvl = 10, .species = SPECIES_CATERPIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherGreg[] = { +static const struct TrainerMon sParty_BugCatcherGreg[] = { { - .iv = 0, .lvl = 9, .species = SPECIES_WEEDLE, }, { - .iv = 0, .lvl = 9, .species = SPECIES_KAKUNA, }, { - .iv = 0, .lvl = 9, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 9, .species = SPECIES_METAPOD, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherJames[] = { +static const struct TrainerMon sParty_BugCatcherJames[] = { { - .iv = 0, .lvl = 11, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 11, .species = SPECIES_METAPOD, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherKent[] = { +static const struct TrainerMon sParty_BugCatcherKent[] = { { - .iv = 0, .lvl = 11, .species = SPECIES_WEEDLE, }, { - .iv = 0, .lvl = 11, .species = SPECIES_KAKUNA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherRobby[] = { +static const struct TrainerMon sParty_BugCatcherRobby[] = { { - .iv = 0, .lvl = 10, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 10, .species = SPECIES_METAPOD, }, { - .iv = 0, .lvl = 10, .species = SPECIES_CATERPIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherCale[] = { +static const struct TrainerMon sParty_BugCatcherCale[] = { { - .iv = 0, .lvl = 10, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 10, .species = SPECIES_WEEDLE, }, { - .iv = 0, .lvl = 10, .species = SPECIES_METAPOD, }, { - .iv = 0, .lvl = 10, .species = SPECIES_KAKUNA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherKeigo[] = { +static const struct TrainerMon sParty_BugCatcherKeigo[] = { { - .iv = 0, .lvl = 16, .species = SPECIES_WEEDLE, }, { - .iv = 0, .lvl = 16, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 16, .species = SPECIES_WEEDLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherElijah[] = { +static const struct TrainerMon sParty_BugCatcherElijah[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_BUTTERFREE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcher2[] = { +static const struct TrainerMon sParty_BugCatcher2[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_METAPOD, }, { - .iv = 0, .lvl = 18, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 18, .species = SPECIES_VENONAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherBrent[] = { +static const struct TrainerMon sParty_BugCatcherBrent[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_BEEDRILL, }, { - .iv = 0, .lvl = 19, .species = SPECIES_BEEDRILL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherConner[] = { +static const struct TrainerMon sParty_BugCatcherConner[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 20, .species = SPECIES_WEEDLE, }, { - .iv = 0, .lvl = 20, .species = SPECIES_VENONAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassJanice[] = { +static const struct TrainerMon sParty_LassJanice[] = { { - .iv = 0, .lvl = 9, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 9, .species = SPECIES_PIDGEY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassSally[] = { +static const struct TrainerMon sParty_LassSally[] = { { - .iv = 0, .lvl = 10, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 10, .species = SPECIES_NIDORAN_F, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassRobin[] = { +static const struct TrainerMon sParty_LassRobin[] = { { - .iv = 0, .lvl = 14, .species = SPECIES_JIGGLYPUFF, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassCrissy[] = { +static const struct TrainerMon sParty_LassCrissy[] = { { - .iv = 0, .lvl = 31, .species = SPECIES_PARAS, }, { - .iv = 0, .lvl = 31, .species = SPECIES_PARAS, }, { - .iv = 0, .lvl = 31, .species = SPECIES_PARASECT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassMiriam[] = { +static const struct TrainerMon sParty_LassMiriam[] = { { - .iv = 0, .lvl = 11, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 11, .species = SPECIES_BELLSPROUT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassIris[] = { +static const struct TrainerMon sParty_LassIris[] = { { - .iv = 0, .lvl = 14, .species = SPECIES_CLEFAIRY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassReli[] = { +static const struct TrainerMon sParty_LassReli[] = { { - .iv = 0, .lvl = 16, .species = SPECIES_NIDORAN_M, }, { - .iv = 0, .lvl = 16, .species = SPECIES_NIDORAN_F, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassAli[] = { +static const struct TrainerMon sParty_LassAli[] = { { - .iv = 0, .lvl = 12, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 12, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 12, .species = SPECIES_BELLSPROUT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Lass2[] = { +static const struct TrainerMon sParty_Lass2[] = { { - .iv = 0, .lvl = 15, .species = SPECIES_NIDORAN_M, }, { - .iv = 0, .lvl = 15, .species = SPECIES_NIDORAN_F, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassHaley[] = { +static const struct TrainerMon sParty_LassHaley[] = { { - .iv = 0, .lvl = 13, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 13, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 13, .species = SPECIES_ODDISH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassAnn[] = { +static const struct TrainerMon sParty_LassAnn[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 18, .species = SPECIES_NIDORAN_F, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassDawn[] = { +static const struct TrainerMon sParty_LassDawn[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 18, .species = SPECIES_PIKACHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassPaige[] = { +static const struct TrainerMon sParty_LassPaige[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_NIDORAN_F, }, { - .iv = 0, .lvl = 23, .species = SPECIES_NIDORINA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassAndrea[] = { +static const struct TrainerMon sParty_LassAndrea[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_MEOWTH, }, { - .iv = 0, .lvl = 24, .species = SPECIES_MEOWTH, }, { - .iv = 0, .lvl = 24, .species = SPECIES_MEOWTH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassMegan[] = { +static const struct TrainerMon sParty_LassMegan[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 19, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 19, .species = SPECIES_NIDORAN_M, }, { - .iv = 0, .lvl = 19, .species = SPECIES_MEOWTH, }, { - .iv = 0, .lvl = 19, .species = SPECIES_PIKACHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassJulia[] = { +static const struct TrainerMon sParty_LassJulia[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_CLEFAIRY, }, { - .iv = 0, .lvl = 22, .species = SPECIES_CLEFAIRY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassKay[] = { +static const struct TrainerMon sParty_LassKay[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_BELLSPROUT, }, { - .iv = 0, .lvl = 23, .species = SPECIES_WEEPINBELL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassLisa[] = { +static const struct TrainerMon sParty_LassLisa[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 23, .species = SPECIES_GLOOM, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SailorEdmond[] = { +static const struct TrainerMon sParty_SailorEdmond[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 18, .species = SPECIES_SHELLDER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SailorTrevor[] = { +static const struct TrainerMon sParty_SailorTrevor[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 17, .species = SPECIES_TENTACOOL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SailorLeonard[] = { +static const struct TrainerMon sParty_SailorLeonard[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_SHELLDER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SailorDuncan[] = { +static const struct TrainerMon sParty_SailorDuncan[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 17, .species = SPECIES_SHELLDER, }, { - .iv = 0, .lvl = 17, .species = SPECIES_TENTACOOL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SailorHuey[] = { +static const struct TrainerMon sParty_SailorHuey[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 18, .species = SPECIES_STARYU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SailorDylan[] = { +static const struct TrainerMon sParty_SailorDylan[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 17, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 17, .species = SPECIES_HORSEA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SailorPhillip[] = { +static const struct TrainerMon sParty_SailorPhillip[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_MACHOP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SailorDwayne[] = { +static const struct TrainerMon sParty_SailorDwayne[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_PIKACHU, }, { - .iv = 0, .lvl = 21, .species = SPECIES_PIKACHU, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CamperLiam[] = { +static const struct TrainerMon sParty_CamperLiam[] = { { - .iv = 0, .lvl = 10, .species = SPECIES_GEODUDE, .moves = {MOVE_TACKLE, MOVE_DEFENSE_CURL, MOVE_NONE, MOVE_NONE}, }, { - .iv = 0, .lvl = 11, .species = SPECIES_SANDSHREW, .moves = {MOVE_SCRATCH, MOVE_DEFENSE_CURL, MOVE_SAND_ATTACK, MOVE_NONE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperShane[] = { +static const struct TrainerMon sParty_CamperShane[] = { { - .iv = 0, .lvl = 14, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 14, .species = SPECIES_EKANS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperEthan[] = { +static const struct TrainerMon sParty_CamperEthan[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_MANKEY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperRicky[] = { +static const struct TrainerMon sParty_CamperRicky[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_SQUIRTLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperJeff[] = { +static const struct TrainerMon sParty_CamperJeff[] = { { - .iv = 0, .lvl = 16, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 16, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Camper2[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Camper2[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperChris[] = { +static const struct TrainerMon sParty_CamperChris[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 21, .species = SPECIES_CHARMANDER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperDrew[] = { +static const struct TrainerMon sParty_CamperDrew[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 19, .species = SPECIES_SANDSHREW, }, { - .iv = 0, .lvl = 19, .species = SPECIES_EKANS, }, { - .iv = 0, .lvl = 19, .species = SPECIES_SANDSHREW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerDiana[] = { +static const struct TrainerMon sParty_PicnickerDiana[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_GOLDEEN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerNancy[] = { +static const struct TrainerMon sParty_PicnickerNancy[] = { { - .iv = 0, .lvl = 16, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 16, .species = SPECIES_PIKACHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerIsabelle[] = { +static const struct TrainerMon sParty_PicnickerIsabelle[] = { { - .iv = 0, .lvl = 16, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 16, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 16, .species = SPECIES_PIDGEY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerKelsey[] = { +static const struct TrainerMon sParty_PicnickerKelsey[] = { { - .iv = 0, .lvl = 15, .species = SPECIES_NIDORAN_M, }, { - .iv = 0, .lvl = 15, .species = SPECIES_NIDORAN_F, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerAlicia[] = { +static const struct TrainerMon sParty_PicnickerAlicia[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 18, .species = SPECIES_BELLSPROUT, }, { - .iv = 0, .lvl = 18, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 18, .species = SPECIES_BELLSPROUT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerCaitlin[] = { +static const struct TrainerMon sParty_PicnickerCaitlin[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_MEOWTH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerHeidi[] = { +static const struct TrainerMon sParty_PicnickerHeidi[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_PIKACHU, }, { - .iv = 0, .lvl = 20, .species = SPECIES_CLEFAIRY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerCarol[] = { +static const struct TrainerMon sParty_PicnickerCarol[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 21, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerSofia[] = { +static const struct TrainerMon sParty_PicnickerSofia[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_JIGGLYPUFF, }, { - .iv = 0, .lvl = 21, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 21, .species = SPECIES_MEOWTH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerMartha[] = { +static const struct TrainerMon sParty_PicnickerMartha[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 22, .species = SPECIES_BULBASAUR, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerTina[] = { +static const struct TrainerMon sParty_PicnickerTina[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_BULBASAUR, }, { - .iv = 0, .lvl = 24, .species = SPECIES_IVYSAUR, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerHannah[] = { +static const struct TrainerMon sParty_PicnickerHannah[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 24, .species = SPECIES_MEOWTH, }, { - .iv = 0, .lvl = 24, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 24, .species = SPECIES_PIKACHU, }, { - .iv = 0, .lvl = 24, .species = SPECIES_MEOWTH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacMark[] = { +static const struct TrainerMon sParty_PokemaniacMark[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 29, .species = SPECIES_RHYHORN, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 29, .species = SPECIES_LICKITUNG, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacHerman[] = { +static const struct TrainerMon sParty_PokemaniacHerman[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 20, .species = SPECIES_CUBONE, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 20, .species = SPECIES_SLOWPOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacCooper[] = { +static const struct TrainerMon sParty_PokemaniacCooper[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 20, .species = SPECIES_SLOWPOKE, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 20, .species = SPECIES_SLOWPOKE, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 20, .species = SPECIES_SLOWPOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacSteve[] = { +static const struct TrainerMon sParty_PokemaniacSteve[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 22, .species = SPECIES_CHARMANDER, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 22, .species = SPECIES_CUBONE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacWinston[] = { +static const struct TrainerMon sParty_PokemaniacWinston[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 25, .species = SPECIES_SLOWPOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacDawson[] = { +static const struct TrainerMon sParty_PokemaniacDawson[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 40, .species = SPECIES_CHARMELEON, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 40, .species = SPECIES_LAPRAS, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 40, .species = SPECIES_LICKITUNG, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacAshton[] = { +static const struct TrainerMon sParty_PokemaniacAshton[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 23, .species = SPECIES_CUBONE, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 23, .species = SPECIES_SLOWPOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerdJovan[] = { +static const struct TrainerMon sParty_SuperNerdJovan[] = { { - .iv = 0, .lvl = 11, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 11, .species = SPECIES_VOLTORB, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerdMiguel[] = { +static const struct TrainerMon sParty_SuperNerdMiguel[] = { { - .iv = 0, .lvl = 12, .species = SPECIES_GRIMER, }, { - .iv = 0, .lvl = 12, .species = SPECIES_VOLTORB, }, { - .iv = 0, .lvl = 12, .species = SPECIES_KOFFING, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_SuperNerdAidan[] = { +static const struct TrainerMon sParty_SuperNerdAidan[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_VOLTORB, .moves = {MOVE_SONIC_BOOM, MOVE_SCREECH, MOVE_TACKLE, MOVE_CHARGE}, }, { - .iv = 0, .lvl = 20, .species = SPECIES_KOFFING, .moves = {MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE, MOVE_POISON_GAS}, }, { - .iv = 0, .lvl = 20, .species = SPECIES_VOLTORB, .moves = {MOVE_SONIC_BOOM, MOVE_SCREECH, MOVE_TACKLE, MOVE_CHARGE}, }, { - .iv = 0, .lvl = 20, .species = SPECIES_MAGNEMITE, .moves = {MOVE_SONIC_BOOM, MOVE_SUPERSONIC, MOVE_THUNDER_SHOCK, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerdGlenn[] = { +static const struct TrainerMon sParty_SuperNerdGlenn[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GRIMER, }, { - .iv = 0, .lvl = 22, .species = SPECIES_MUK, }, { - .iv = 0, .lvl = 22, .species = SPECIES_GRIMER, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_SuperNerdLeslie[] = { +static const struct TrainerMon sParty_SuperNerdLeslie[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_KOFFING, .moves = {MOVE_SLUDGE, MOVE_SMOKESCREEN, MOVE_SMOG, MOVE_SELF_DESTRUCT}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerd1[] = { +static const struct TrainerMon sParty_SuperNerd1[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_KOFFING, }, { - .iv = 0, .lvl = 22, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 22, .species = SPECIES_WEEZING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerd2[] = { +static const struct TrainerMon sParty_SuperNerd2[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 20, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 20, .species = SPECIES_KOFFING, }, { - .iv = 0, .lvl = 20, .species = SPECIES_MAGNEMITE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerd3[] = { +static const struct TrainerMon sParty_SuperNerd3[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 24, .species = SPECIES_VOLTORB, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerdErik[] = { +static const struct TrainerMon sParty_SuperNerdErik[] = { { - .iv = 0, .lvl = 36, .species = SPECIES_VULPIX, }, { - .iv = 0, .lvl = 36, .species = SPECIES_VULPIX, }, { - .iv = 0, .lvl = 36, .species = SPECIES_NINETALES, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerdAvery[] = { +static const struct TrainerMon sParty_SuperNerdAvery[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_PONYTA, }, { - .iv = 0, .lvl = 34, .species = SPECIES_CHARMANDER, }, { - .iv = 0, .lvl = 34, .species = SPECIES_VULPIX, }, { - .iv = 0, .lvl = 34, .species = SPECIES_GROWLITHE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerdDerek[] = { +static const struct TrainerMon sParty_SuperNerdDerek[] = { { - .iv = 0, .lvl = 41, .species = SPECIES_RAPIDASH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerdZac[] = { +static const struct TrainerMon sParty_SuperNerdZac[] = { { - .iv = 0, .lvl = 37, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 37, .species = SPECIES_VULPIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerMarcos[] = { +static const struct TrainerMon sParty_HikerMarcos[] = { { - .iv = 0, .lvl = 10, .species = SPECIES_GEODUDE, }, { - .iv = 0, .lvl = 10, .species = SPECIES_GEODUDE, }, { - .iv = 0, .lvl = 10, .species = SPECIES_ONIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerFranklin[] = { +static const struct TrainerMon sParty_HikerFranklin[] = { { - .iv = 0, .lvl = 15, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 15, .species = SPECIES_GEODUDE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerNob[] = { +static const struct TrainerMon sParty_HikerNob[] = { { - .iv = 0, .lvl = 13, .species = SPECIES_GEODUDE, }, { - .iv = 0, .lvl = 13, .species = SPECIES_GEODUDE, }, { - .iv = 0, .lvl = 13, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 13, .species = SPECIES_GEODUDE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerWayne[] = { +static const struct TrainerMon sParty_HikerWayne[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_ONIX, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_HikerAlan[] = { +static const struct TrainerMon sParty_HikerAlan[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_GEODUDE, .moves = {MOVE_MAGNITUDE, MOVE_ROCK_THROW, MOVE_MUD_SPORT, MOVE_DEFENSE_CURL}, }, { - .iv = 0, .lvl = 21, .species = SPECIES_ONIX, .moves = {MOVE_HARDEN, MOVE_ROCK_THROW, MOVE_BIND, MOVE_SCREECH}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerBrice[] = { +static const struct TrainerMon sParty_HikerBrice[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_GEODUDE, }, { - .iv = 0, .lvl = 20, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 20, .species = SPECIES_GEODUDE, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_HikerClark[] = { +static const struct TrainerMon sParty_HikerClark[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_GEODUDE, .moves = {MOVE_MAGNITUDE, MOVE_ROCK_THROW, MOVE_MUD_SPORT, MOVE_DEFENSE_CURL}, }, { - .iv = 0, .lvl = 21, .species = SPECIES_ONIX, .moves = {MOVE_HARDEN, MOVE_ROCK_THROW, MOVE_BIND, MOVE_SCREECH}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerTrent[] = { +static const struct TrainerMon sParty_HikerTrent[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_ONIX, }, { - .iv = 0, .lvl = 19, .species = SPECIES_GRAVELER, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_HikerDudley[] = { +static const struct TrainerMon sParty_HikerDudley[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_GEODUDE, .moves = {MOVE_MAGNITUDE, MOVE_ROCK_THROW, MOVE_MUD_SPORT, MOVE_DEFENSE_CURL}, }, { - .iv = 0, .lvl = 21, .species = SPECIES_GEODUDE, .moves = {MOVE_MAGNITUDE, MOVE_ROCK_THROW, MOVE_MUD_SPORT, MOVE_DEFENSE_CURL}, }, { - .iv = 0, .lvl = 21, .species = SPECIES_GRAVELER, .moves = {MOVE_MAGNITUDE, MOVE_ROCK_THROW, MOVE_MUD_SPORT, MOVE_DEFENSE_CURL}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_HikerAllen[] = { +static const struct TrainerMon sParty_HikerAllen[] = { { - .iv = 0, .lvl = 25, .species = SPECIES_GEODUDE, .moves = {MOVE_MAGNITUDE, MOVE_ROCK_THROW, MOVE_MUD_SPORT, MOVE_DEFENSE_CURL}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerEric[] = { +static const struct TrainerMon sParty_HikerEric[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 20, .species = SPECIES_ONIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerLenny[] = { +static const struct TrainerMon sParty_HikerLenny[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_GEODUDE, }, { - .iv = 0, .lvl = 19, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 19, .species = SPECIES_GEODUDE, }, { - .iv = 0, .lvl = 19, .species = SPECIES_GEODUDE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerOliver[] = { +static const struct TrainerMon sParty_HikerOliver[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_ONIX, }, { - .iv = 0, .lvl = 20, .species = SPECIES_ONIX, }, { - .iv = 0, .lvl = 20, .species = SPECIES_GEODUDE, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_HikerLucas[] = { +static const struct TrainerMon sParty_HikerLucas[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_GEODUDE, .moves = {MOVE_MAGNITUDE, MOVE_ROCK_THROW, MOVE_MUD_SPORT, MOVE_DEFENSE_CURL}, }, { - .iv = 0, .lvl = 21, .species = SPECIES_GRAVELER, .moves = {MOVE_MAGNITUDE, MOVE_ROCK_THROW, MOVE_MUD_SPORT, MOVE_DEFENSE_CURL}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerJared[] = { +static const struct TrainerMon sParty_BikerJared[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_POISON_GAS}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerMalik[] = { +static const struct TrainerMon sParty_BikerMalik[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 29, .species = SPECIES_GRIMER, .moves = {MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerErnest[] = { +static const struct TrainerMon sParty_BikerErnest[] = { { - .iv = 0, .lvl = 25, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_GRIMER, .moves = {MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE, MOVE_POUND}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerAlex[] = { +static const struct TrainerMon sParty_BikerAlex[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_GRIMER, .moves = {MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerLao[] = { +static const struct TrainerMon sParty_BikerLao[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_GRIMER, .moves = {MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE}, }, { - .iv = 0, .lvl = 29, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Biker1[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Biker1[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BikerHideo[] = { +static const struct TrainerMon sParty_BikerHideo[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_WEEZING, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerRuben[] = { +static const struct TrainerMon sParty_BikerRuben[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BikerBilly[] = { +static const struct TrainerMon sParty_BikerBilly[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_MUK, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerNikolas[] = { +static const struct TrainerMon sParty_BikerNikolas[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_VOLTORB, .moves = {MOVE_SPARK, MOVE_SONIC_BOOM, MOVE_SCREECH, MOVE_CHARGE}, }, { - .iv = 0, .lvl = 29, .species = SPECIES_VOLTORB, .moves = {MOVE_SPARK, MOVE_SONIC_BOOM, MOVE_SCREECH, MOVE_CHARGE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerJaxon[] = { +static const struct TrainerMon sParty_BikerJaxon[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_WEEZING, .moves = {MOVE_SLUDGE, MOVE_SMOKESCREEN, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MUK, .moves = {MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerWilliam[] = { +static const struct TrainerMon sParty_BikerWilliam[] = { { - .iv = 0, .lvl = 25, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SELF_DESTRUCT, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerLukas[] = { +static const struct TrainerMon sParty_BikerLukas[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_GRIMER, .moves = {MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerIsaac[] = { +static const struct TrainerMon sParty_BikerIsaac[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_GRIMER, .moves = {MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_GRIMER, .moves = {MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerGerald[] = { +static const struct TrainerMon sParty_BikerGerald[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MUK, .moves = {MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Burglar1[] = { +static const struct TrainerMon sParty_Burglar1[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 29, .species = SPECIES_VULPIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Burglar2[] = { +static const struct TrainerMon sParty_Burglar2[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_GROWLITHE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Burglar3[] = { +static const struct TrainerMon sParty_Burglar3[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_VULPIX, }, { - .iv = 0, .lvl = 28, .species = SPECIES_CHARMANDER, }, { - .iv = 0, .lvl = 28, .species = SPECIES_PONYTA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BurglarQuinn[] = { +static const struct TrainerMon sParty_BurglarQuinn[] = { { - .iv = 0, .lvl = 36, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 36, .species = SPECIES_VULPIX, }, { - .iv = 0, .lvl = 36, .species = SPECIES_NINETALES, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BurglarRamon[] = { +static const struct TrainerMon sParty_BurglarRamon[] = { { - .iv = 0, .lvl = 41, .species = SPECIES_PONYTA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BurglarDusty[] = { +static const struct TrainerMon sParty_BurglarDusty[] = { { - .iv = 0, .lvl = 37, .species = SPECIES_VULPIX, }, { - .iv = 0, .lvl = 37, .species = SPECIES_GROWLITHE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BurglarArnie[] = { +static const struct TrainerMon sParty_BurglarArnie[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_CHARMANDER, }, { - .iv = 0, .lvl = 34, .species = SPECIES_CHARMELEON, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Burglar4[] = { +static const struct TrainerMon sParty_Burglar4[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_CHARMANDER, }, { - .iv = 0, .lvl = 34, .species = SPECIES_CHARMELEON, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BurglarSimon[] = { +static const struct TrainerMon sParty_BurglarSimon[] = { { - .iv = 0, .lvl = 38, .species = SPECIES_NINETALES, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BurglarLewis[] = { +static const struct TrainerMon sParty_BurglarLewis[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 34, .species = SPECIES_PONYTA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_EngineerBaily[] = { +static const struct TrainerMon sParty_EngineerBaily[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_VOLTORB, }, { - .iv = 0, .lvl = 21, .species = SPECIES_MAGNEMITE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_EngineerBraxton[] = { +static const struct TrainerMon sParty_EngineerBraxton[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_MAGNEMITE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_EngineerBernie[] = { +static const struct TrainerMon sParty_EngineerBernie[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 18, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 18, .species = SPECIES_MAGNETON, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanDale[] = { +static const struct TrainerMon sParty_FishermanDale[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 17, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 17, .species = SPECIES_GOLDEEN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanBarny[] = { +static const struct TrainerMon sParty_FishermanBarny[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 17, .species = SPECIES_STARYU, }, { - .iv = 0, .lvl = 17, .species = SPECIES_SHELLDER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanNed[] = { +static const struct TrainerMon sParty_FishermanNed[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 22, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 22, .species = SPECIES_GOLDEEN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanChip[] = { +static const struct TrainerMon sParty_FishermanChip[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 24, .species = SPECIES_GOLDEEN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanHank[] = { +static const struct TrainerMon sParty_FishermanHank[] = { { - .iv = 0, .lvl = 27, .species = SPECIES_GOLDEEN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanElliot[] = { +static const struct TrainerMon sParty_FishermanElliot[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 21, .species = SPECIES_SHELLDER, }, { - .iv = 0, .lvl = 21, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 21, .species = SPECIES_HORSEA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanRonald[] = { +static const struct TrainerMon sParty_FishermanRonald[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_SEAKING, }, { - .iv = 0, .lvl = 28, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 28, .species = SPECIES_SEAKING, }, { - .iv = 0, .lvl = 28, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanClaude[] = { +static const struct TrainerMon sParty_FishermanClaude[] = { { - .iv = 0, .lvl = 31, .species = SPECIES_SHELLDER, }, { - .iv = 0, .lvl = 31, .species = SPECIES_CLOYSTER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanWade[] = { +static const struct TrainerMon sParty_FishermanWade[] = { { - .iv = 0, .lvl = 27, .species = SPECIES_MAGIKARP, }, { - .iv = 0, .lvl = 27, .species = SPECIES_MAGIKARP, }, { - .iv = 0, .lvl = 27, .species = SPECIES_MAGIKARP, }, { - .iv = 0, .lvl = 27, .species = SPECIES_MAGIKARP, }, { - .iv = 0, .lvl = 27, .species = SPECIES_MAGIKARP, }, { - .iv = 0, .lvl = 27, .species = SPECIES_MAGIKARP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanNolan[] = { +static const struct TrainerMon sParty_FishermanNolan[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_SEAKING, }, { - .iv = 0, .lvl = 33, .species = SPECIES_GOLDEEN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanAndrew[] = { +static const struct TrainerMon sParty_FishermanAndrew[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_MAGIKARP, }, { - .iv = 0, .lvl = 24, .species = SPECIES_MAGIKARP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleLuis[] = { +static const struct TrainerMon sParty_SwimmerMaleLuis[] = { { - .iv = 0, .lvl = 16, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 16, .species = SPECIES_SHELLDER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleRichard[] = { +static const struct TrainerMon sParty_SwimmerMaleRichard[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 30, .species = SPECIES_SHELLDER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleReece[] = { +static const struct TrainerMon sParty_SwimmerMaleReece[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 29, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 29, .species = SPECIES_STARYU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleMatthew[] = { +static const struct TrainerMon sParty_SwimmerMaleMatthew[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 30, .species = SPECIES_POLIWHIRL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleDouglas[] = { +static const struct TrainerMon sParty_SwimmerMaleDouglas[] = { { - .iv = 0, .lvl = 27, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 27, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 27, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 27, .species = SPECIES_GOLDEEN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleDavid[] = { +static const struct TrainerMon sParty_SwimmerMaleDavid[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 29, .species = SPECIES_SHELLDER, }, { - .iv = 0, .lvl = 29, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleTony[] = { +static const struct TrainerMon sParty_SwimmerMaleTony[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 30, .species = SPECIES_HORSEA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleAxle[] = { +static const struct TrainerMon sParty_SwimmerMaleAxle[] = { { - .iv = 0, .lvl = 27, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 27, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 27, .species = SPECIES_STARYU, }, { - .iv = 0, .lvl = 27, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 27, .species = SPECIES_TENTACRUEL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleBarry[] = { +static const struct TrainerMon sParty_SwimmerMaleBarry[] = { { - .iv = 0, .lvl = 31, .species = SPECIES_SHELLDER, }, { - .iv = 0, .lvl = 31, .species = SPECIES_CLOYSTER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleDean[] = { +static const struct TrainerMon sParty_SwimmerMaleDean[] = { { - .iv = 0, .lvl = 35, .species = SPECIES_STARYU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleDarrin[] = { +static const struct TrainerMon sParty_SwimmerMaleDarrin[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 28, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 28, .species = SPECIES_SEADRA, }, { - .iv = 0, .lvl = 28, .species = SPECIES_HORSEA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleSpencer[] = { +static const struct TrainerMon sParty_SwimmerMaleSpencer[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_SEADRA, }, { - .iv = 0, .lvl = 33, .species = SPECIES_TENTACRUEL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleJack[] = { +static const struct TrainerMon sParty_SwimmerMaleJack[] = { { - .iv = 0, .lvl = 37, .species = SPECIES_STARMIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleJerome[] = { +static const struct TrainerMon sParty_SwimmerMaleJerome[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_STARYU, }, { - .iv = 0, .lvl = 33, .species = SPECIES_WARTORTLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleRoland[] = { +static const struct TrainerMon sParty_SwimmerMaleRoland[] = { { - .iv = 0, .lvl = 32, .species = SPECIES_POLIWHIRL, }, { - .iv = 0, .lvl = 32, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 32, .species = SPECIES_SEADRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallKoji[] = { +static const struct TrainerMon sParty_CueBallKoji[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 28, .species = SPECIES_MANKEY, }, { - .iv = 0, .lvl = 28, .species = SPECIES_MACHOP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallLuke[] = { +static const struct TrainerMon sParty_CueBallLuke[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_MANKEY, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MACHOP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallCamron[] = { +static const struct TrainerMon sParty_CueBallCamron[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_MANKEY, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MACHOP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallRaul[] = { +static const struct TrainerMon sParty_CueBallRaul[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_MANKEY, }, { - .iv = 0, .lvl = 29, .species = SPECIES_PRIMEAPE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallIsaiah[] = { +static const struct TrainerMon sParty_CueBallIsaiah[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MACHAMP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallZeek[] = { +static const struct TrainerMon sParty_CueBallZeek[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_MACHOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallJamal[] = { +static const struct TrainerMon sParty_CueBallJamal[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_MANKEY, }, { - .iv = 0, .lvl = 26, .species = SPECIES_MANKEY, }, { - .iv = 0, .lvl = 26, .species = SPECIES_MACHAMP, }, { - .iv = 0, .lvl = 26, .species = SPECIES_MACHOP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallCorey[] = { +static const struct TrainerMon sParty_CueBallCorey[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_PRIMEAPE, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MACHOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallChase[] = { +static const struct TrainerMon sParty_CueBallChase[] = { { - .iv = 0, .lvl = 31, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 31, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 31, .species = SPECIES_TENTACRUEL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GamerHugo[] = { +static const struct TrainerMon sParty_GamerHugo[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 18, .species = SPECIES_HORSEA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GamerJasper[] = { +static const struct TrainerMon sParty_GamerJasper[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_BELLSPROUT, }, { - .iv = 0, .lvl = 18, .species = SPECIES_ODDISH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GamerDirk[] = { +static const struct TrainerMon sParty_GamerDirk[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_VOLTORB, }, { - .iv = 0, .lvl = 18, .species = SPECIES_MAGNEMITE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GamerDarian[] = { +static const struct TrainerMon sParty_GamerDarian[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 18, .species = SPECIES_VULPIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GamerStan[] = { +static const struct TrainerMon sParty_GamerStan[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 22, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 22, .species = SPECIES_POLIWHIRL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Gamer1[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Gamer1[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_GamerRich[] = { +static const struct TrainerMon sParty_GamerRich[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 24, .species = SPECIES_VULPIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautyBridget[] = { +static const struct TrainerMon sParty_BeautyBridget[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 21, .species = SPECIES_BELLSPROUT, }, { - .iv = 0, .lvl = 21, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 21, .species = SPECIES_BELLSPROUT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautyTamia[] = { +static const struct TrainerMon sParty_BeautyTamia[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_BELLSPROUT, }, { - .iv = 0, .lvl = 24, .species = SPECIES_BELLSPROUT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautyLori[] = { +static const struct TrainerMon sParty_BeautyLori[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_EXEGGCUTE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautyLola[] = { +static const struct TrainerMon sParty_BeautyLola[] = { { - .iv = 0, .lvl = 27, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 27, .species = SPECIES_PIKACHU, }, { - .iv = 0, .lvl = 27, .species = SPECIES_RATTATA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautySheila[] = { +static const struct TrainerMon sParty_BeautySheila[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_CLEFAIRY, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MEOWTH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleTiffany[] = { +static const struct TrainerMon sParty_SwimmerFemaleTiffany[] = { { - .iv = 0, .lvl = 35, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleNora[] = { +static const struct TrainerMon sParty_SwimmerFemaleNora[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_SHELLDER, }, { - .iv = 0, .lvl = 30, .species = SPECIES_SHELLDER, }, { - .iv = 0, .lvl = 30, .species = SPECIES_CLOYSTER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleMelissa[] = { +static const struct TrainerMon sParty_SwimmerFemaleMelissa[] = { { - .iv = 0, .lvl = 31, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 31, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautyGrace[] = { +static const struct TrainerMon sParty_BeautyGrace[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_PIDGEOTTO, }, { - .iv = 0, .lvl = 29, .species = SPECIES_WIGGLYTUFF, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautyOlivia[] = { +static const struct TrainerMon sParty_BeautyOlivia[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_BULBASAUR, }, { - .iv = 0, .lvl = 29, .species = SPECIES_IVYSAUR, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautyLauren[] = { +static const struct TrainerMon sParty_BeautyLauren[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_WEEPINBELL, }, { - .iv = 0, .lvl = 33, .species = SPECIES_BELLSPROUT, }, { - .iv = 0, .lvl = 33, .species = SPECIES_WEEPINBELL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleAnya[] = { +static const struct TrainerMon sParty_SwimmerFemaleAnya[] = { { - .iv = 0, .lvl = 27, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 27, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 27, .species = SPECIES_SEAKING, }, { - .iv = 0, .lvl = 27, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 27, .species = SPECIES_POLIWAG, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleAlice[] = { +static const struct TrainerMon sParty_SwimmerFemaleAlice[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 30, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleConnie[] = { +static const struct TrainerMon sParty_SwimmerFemaleConnie[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_STARYU, }, { - .iv = 0, .lvl = 29, .species = SPECIES_STARYU, }, { - .iv = 0, .lvl = 29, .species = SPECIES_STARYU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleShirley[] = { +static const struct TrainerMon sParty_SwimmerFemaleShirley[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_SEADRA, }, { - .iv = 0, .lvl = 30, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 30, .species = SPECIES_SEADRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PsychicJohan[] = { +static const struct TrainerMon sParty_PsychicJohan[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 31, .species = SPECIES_KADABRA, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 31, .species = SPECIES_SLOWPOKE, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 31, .species = SPECIES_MR_MIME, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 31, .species = SPECIES_KADABRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PsychicTyron[] = { +static const struct TrainerMon sParty_PsychicTyron[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 34, .species = SPECIES_MR_MIME, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 34, .species = SPECIES_KADABRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PsychicCameron[] = { +static const struct TrainerMon sParty_PsychicCameron[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 33, .species = SPECIES_SLOWPOKE, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 33, .species = SPECIES_SLOWPOKE, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 33, .species = SPECIES_SLOWBRO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PsychicPreston[] = { +static const struct TrainerMon sParty_PsychicPreston[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 38, .species = SPECIES_SLOWBRO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RockerRandall[] = { +static const struct TrainerMon sParty_RockerRandall[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_VOLTORB, }, { - .iv = 0, .lvl = 20, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 20, .species = SPECIES_VOLTORB, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RockerLuca[] = { +static const struct TrainerMon sParty_RockerLuca[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_VOLTORB, }, { - .iv = 0, .lvl = 29, .species = SPECIES_ELECTRODE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_JugglerDalton[] = { +static const struct TrainerMon sParty_JugglerDalton[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_KADABRA, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MR_MIME, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_JugglerNelson[] = { +static const struct TrainerMon sParty_JugglerNelson[] = { { - .iv = 0, .lvl = 41, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 41, .species = SPECIES_HYPNO, }, { - .iv = 0, .lvl = 41, .species = SPECIES_KADABRA, }, { - .iv = 0, .lvl = 41, .species = SPECIES_KADABRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_JugglerKirk[] = { +static const struct TrainerMon sParty_JugglerKirk[] = { { - .iv = 0, .lvl = 31, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 31, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 31, .species = SPECIES_KADABRA, }, { - .iv = 0, .lvl = 31, .species = SPECIES_DROWZEE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_JugglerShawn[] = { +static const struct TrainerMon sParty_JugglerShawn[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 34, .species = SPECIES_HYPNO, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_JugglerGregory[] = { +static const struct TrainerMon sParty_JugglerGregory[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_MR_MIME, .moves = {MOVE_PSYCHIC, MOVE_ROLE_PLAY, MOVE_DOUBLE_SLAP, MOVE_ENCORE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_JugglerEdward[] = { +static const struct TrainerMon sParty_JugglerEdward[] = { { - .iv = 0, .lvl = 46, .species = SPECIES_VOLTORB, .moves = {MOVE_SWIFT, MOVE_LIGHT_SCREEN, MOVE_SPARK, MOVE_SONIC_BOOM}, }, { - .iv = 0, .lvl = 46, .species = SPECIES_VOLTORB, .moves = {MOVE_SWIFT, MOVE_LIGHT_SCREEN, MOVE_SPARK, MOVE_SONIC_BOOM}, }, { - .iv = 0, .lvl = 47, .species = SPECIES_ELECTRODE, .moves = {MOVE_SWIFT, MOVE_SPARK, MOVE_SELF_DESTRUCT, MOVE_SONIC_BOOM}, }, { - .iv = 0, .lvl = 48, .species = SPECIES_MR_MIME, .moves = {MOVE_PSYCHIC, MOVE_ROLE_PLAY, MOVE_REFLECT, MOVE_ENCORE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_JugglerKayden[] = { +static const struct TrainerMon sParty_JugglerKayden[] = { { - .iv = 0, .lvl = 38, .species = SPECIES_HYPNO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_JugglerNate[] = { +static const struct TrainerMon sParty_JugglerNate[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 34, .species = SPECIES_KADABRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TamerPhil[] = { +static const struct TrainerMon sParty_TamerPhil[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 34, .species = SPECIES_SANDSLASH, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 34, .species = SPECIES_ARBOK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TamerEdgar[] = { +static const struct TrainerMon sParty_TamerEdgar[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 33, .species = SPECIES_ARBOK, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 33, .species = SPECIES_SANDSLASH, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 33, .species = SPECIES_ARBOK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TamerJason[] = { +static const struct TrainerMon sParty_TamerJason[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 43, .species = SPECIES_RHYHORN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TamerCole[] = { +static const struct TrainerMon sParty_TamerCole[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 39, .species = SPECIES_ARBOK, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 39, .species = SPECIES_TAUROS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TamerVincent[] = { +static const struct TrainerMon sParty_TamerVincent[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 44, .species = SPECIES_PERSIAN, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 44, .species = SPECIES_GOLDUCK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TamerJohn[] = { +static const struct TrainerMon sParty_TamerJohn[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 42, .species = SPECIES_RHYHORN, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 42, .species = SPECIES_PRIMEAPE, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 42, .species = SPECIES_ARBOK, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 42, .species = SPECIES_TAUROS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperSebastian[] = { +static const struct TrainerMon sParty_BirdKeeperSebastian[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 29, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperPerry[] = { +static const struct TrainerMon sParty_BirdKeeperPerry[] = { { - .iv = 0, .lvl = 25, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 25, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 25, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 25, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 25, .species = SPECIES_SPEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperRobert[] = { +static const struct TrainerMon sParty_BirdKeeperRobert[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 26, .species = SPECIES_PIDGEOTTO, }, { - .iv = 0, .lvl = 26, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 26, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperDonald[] = { +static const struct TrainerMon sParty_BirdKeeperDonald[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_FARFETCHD, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperBenny[] = { +static const struct TrainerMon sParty_BirdKeeperBenny[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 29, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperEdwin[] = { +static const struct TrainerMon sParty_BirdKeeperEdwin[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_PIDGEOTTO, }, { - .iv = 0, .lvl = 26, .species = SPECIES_FARFETCHD, }, { - .iv = 0, .lvl = 26, .species = SPECIES_DODUO, }, { - .iv = 0, .lvl = 26, .species = SPECIES_PIDGEY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperChester[] = { +static const struct TrainerMon sParty_BirdKeeperChester[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_DODRIO, }, { - .iv = 0, .lvl = 28, .species = SPECIES_DODUO, }, { - .iv = 0, .lvl = 28, .species = SPECIES_DODUO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperWilton[] = { +static const struct TrainerMon sParty_BirdKeeperWilton[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 29, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperRamiro[] = { +static const struct TrainerMon sParty_BirdKeeperRamiro[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_DODRIO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperJacob[] = { +static const struct TrainerMon sParty_BirdKeeperJacob[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 26, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 26, .species = SPECIES_FEAROW, }, { - .iv = 0, .lvl = 26, .species = SPECIES_SPEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperRoger[] = { +static const struct TrainerMon sParty_BirdKeeperRoger[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_FEAROW, }, { - .iv = 0, .lvl = 30, .species = SPECIES_FEAROW, }, { - .iv = 0, .lvl = 30, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperReed[] = { +static const struct TrainerMon sParty_BirdKeeperReed[] = { { - .iv = 0, .lvl = 39, .species = SPECIES_PIDGEOTTO, }, { - .iv = 0, .lvl = 39, .species = SPECIES_PIDGEOTTO, }, { - .iv = 0, .lvl = 39, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 39, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperKeith[] = { +static const struct TrainerMon sParty_BirdKeeperKeith[] = { { - .iv = 0, .lvl = 39, .species = SPECIES_FARFETCHD, }, { - .iv = 0, .lvl = 39, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperCarter[] = { +static const struct TrainerMon sParty_BirdKeeperCarter[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 28, .species = SPECIES_DODUO, }, { - .iv = 0, .lvl = 28, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperMitch[] = { +static const struct TrainerMon sParty_BirdKeeperMitch[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 26, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 26, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 26, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperBeck[] = { +static const struct TrainerMon sParty_BirdKeeperBeck[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_PIDGEOTTO, }, { - .iv = 0, .lvl = 29, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperMarlon[] = { +static const struct TrainerMon sParty_BirdKeeperMarlon[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 28, .species = SPECIES_DODUO, }, { - .iv = 0, .lvl = 28, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltKoichi[] = { +static const struct TrainerMon sParty_BlackBeltKoichi[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_HITMONLEE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltMike[] = { +static const struct TrainerMon sParty_BlackBeltMike[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 31, .species = SPECIES_MANKEY, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 31, .species = SPECIES_MANKEY, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 31, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltHideki[] = { +static const struct TrainerMon sParty_BlackBeltHideki[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 32, .species = SPECIES_MACHOP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 32, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltAaron[] = { +static const struct TrainerMon sParty_BlackBeltAaron[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 36, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltHitoshi[] = { +static const struct TrainerMon sParty_BlackBeltHitoshi[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 31, .species = SPECIES_MACHOP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 31, .species = SPECIES_MANKEY, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 31, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltAtsushi[] = { +static const struct TrainerMon sParty_BlackBeltAtsushi[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 40, .species = SPECIES_MACHOP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 40, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltKiyo[] = { +static const struct TrainerMon sParty_BlackBeltKiyo[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 43, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltTakashi[] = { +static const struct TrainerMon sParty_BlackBeltTakashi[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_MACHOP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltDaisuke[] = { +static const struct TrainerMon sParty_BlackBeltDaisuke[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 43, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 43, .species = SPECIES_MACHOP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 43, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalOaksLabSquirtle[] = { +static const struct TrainerMon sParty_RivalOaksLabSquirtle[] = { { - .iv = 0, .lvl = 5, .species = SPECIES_SQUIRTLE, + .moves = {MOVE_TACKLE, MOVE_TAIL_WHIP, MOVE_NONE, MOVE_NONE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalOaksLabBulbasaur[] = { +static const struct TrainerMon sParty_RivalOaksLabBulbasaur[] = { { - .iv = 0, .lvl = 5, .species = SPECIES_BULBASAUR, + .moves = {MOVE_TACKLE, MOVE_GROWL, MOVE_NONE, MOVE_NONE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalOaksLabCharmander[] = { +static const struct TrainerMon sParty_RivalOaksLabCharmander[] = { { - .iv = 0, .lvl = 5, .species = SPECIES_CHARMANDER, + .moves = {MOVE_SCRATCH, MOVE_GROWL, MOVE_NONE, MOVE_NONE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RivalRoute22EarlySquirtle[] = { +static const struct TrainerMon sParty_RivalRoute22EarlySquirtle[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 9, .species = SPECIES_PIDGEY, .moves = {MOVE_TACKLE, MOVE_SAND_ATTACK, MOVE_NONE, MOVE_NONE}, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 9, .species = SPECIES_SQUIRTLE, .moves = {MOVE_TACKLE, MOVE_TAIL_WHIP, MOVE_NONE, MOVE_NONE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RivalRoute22EarlyBulbasaur[] = { +static const struct TrainerMon sParty_RivalRoute22EarlyBulbasaur[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 9, .species = SPECIES_PIDGEY, .moves = {MOVE_TACKLE, MOVE_SAND_ATTACK, MOVE_NONE, MOVE_NONE}, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 9, .species = SPECIES_BULBASAUR, .moves = {MOVE_TACKLE, MOVE_GROWL, MOVE_NONE, MOVE_NONE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RivalRoute22EarlyCharmander[] = { +static const struct TrainerMon sParty_RivalRoute22EarlyCharmander[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 9, .species = SPECIES_PIDGEY, .moves = {MOVE_TACKLE, MOVE_SAND_ATTACK, MOVE_NONE, MOVE_NONE}, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 9, .species = SPECIES_CHARMANDER, .moves = {MOVE_SCRATCH, MOVE_GROWL, MOVE_NONE, MOVE_NONE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RivalCeruleanSquirtle[] = { +static const struct TrainerMon sParty_RivalCeruleanSquirtle[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 17, .species = SPECIES_PIDGEOTTO, .moves = {MOVE_TACKLE, MOVE_SAND_ATTACK, MOVE_GUST, MOVE_QUICK_ATTACK}, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 16, .species = SPECIES_ABRA, .moves = {MOVE_TELEPORT, MOVE_NONE, MOVE_NONE, MOVE_NONE}, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 15, .species = SPECIES_RATTATA, .moves = {MOVE_TACKLE, MOVE_TAIL_WHIP, MOVE_QUICK_ATTACK, MOVE_NONE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 18, .species = SPECIES_SQUIRTLE, .moves = {MOVE_TACKLE, MOVE_TAIL_WHIP, MOVE_WITHDRAW, MOVE_WATER_GUN}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RivalCeruleanBulbasaur[] = { +static const struct TrainerMon sParty_RivalCeruleanBulbasaur[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 17, .species = SPECIES_PIDGEOTTO, .moves = {MOVE_TACKLE, MOVE_SAND_ATTACK, MOVE_GUST, MOVE_QUICK_ATTACK}, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 16, .species = SPECIES_ABRA, .moves = {MOVE_TELEPORT, MOVE_NONE, MOVE_NONE, MOVE_NONE}, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 15, .species = SPECIES_RATTATA, .moves = {MOVE_TACKLE, MOVE_TAIL_WHIP, MOVE_QUICK_ATTACK, MOVE_NONE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 18, .species = SPECIES_BULBASAUR, .moves = {MOVE_SLEEP_POWDER, MOVE_POISON_POWDER, MOVE_VINE_WHIP, MOVE_LEECH_SEED}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RivalCeruleanCharmander[] = { +static const struct TrainerMon sParty_RivalCeruleanCharmander[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 17, .species = SPECIES_PIDGEOTTO, .moves = {MOVE_TACKLE, MOVE_SAND_ATTACK, MOVE_GUST, MOVE_QUICK_ATTACK}, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 16, .species = SPECIES_ABRA, .moves = {MOVE_TELEPORT, MOVE_NONE, MOVE_NONE, MOVE_NONE}, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 15, .species = SPECIES_RATTATA, .moves = {MOVE_TACKLE, MOVE_TAIL_WHIP, MOVE_QUICK_ATTACK, MOVE_NONE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 18, .species = SPECIES_CHARMANDER, .moves = {MOVE_METAL_CLAW, MOVE_EMBER, MOVE_GROWL, MOVE_SCRATCH}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ScientistTed[] = { +static const struct TrainerMon sParty_ScientistTed[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_ELECTRODE, }, { - .iv = 0, .lvl = 29, .species = SPECIES_WEEZING, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_ScientistConnor[] = { +static const struct TrainerMon sParty_ScientistConnor[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_GRIMER, .moves = {MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_SELF_DESTRUCT}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ScientistJerry[] = { +static const struct TrainerMon sParty_ScientistJerry[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 28, .species = SPECIES_VOLTORB, }, { - .iv = 0, .lvl = 28, .species = SPECIES_MAGNETON, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_ScientistJose[] = { +static const struct TrainerMon sParty_ScientistJose[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_ELECTRODE, .moves = {MOVE_SPARK, MOVE_SONIC_BOOM, MOVE_SCREECH, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 29, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ScientistRodney[] = { +static const struct TrainerMon sParty_ScientistRodney[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_ELECTRODE, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_ScientistBeau[] = { +static const struct TrainerMon sParty_ScientistBeau[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_MAGNETON, .moves = {MOVE_SPARK, MOVE_THUNDER_WAVE, MOVE_SONIC_BOOM, MOVE_SUPERSONIC}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_MAGNEMITE, .moves = {MOVE_SPARK, MOVE_THUNDER_WAVE, MOVE_SONIC_BOOM, MOVE_SUPERSONIC}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_ScientistTaylor[] = { +static const struct TrainerMon sParty_ScientistTaylor[] = { { - .iv = 0, .lvl = 25, .species = SPECIES_VOLTORB, .moves = {MOVE_SPARK, MOVE_SONIC_BOOM, MOVE_SCREECH, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_MAGNETON, .moves = {MOVE_THUNDER_WAVE, MOVE_SONIC_BOOM, MOVE_SUPERSONIC, MOVE_THUNDER_SHOCK}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_MAGNEMITE, .moves = {MOVE_THUNDER_WAVE, MOVE_SONIC_BOOM, MOVE_SUPERSONIC, MOVE_THUNDER_SHOCK}, }, { - .iv = 0, .lvl = 25, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_SELF_DESTRUCT}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ScientistJoshua[] = { +static const struct TrainerMon sParty_ScientistJoshua[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_ELECTRODE, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MUK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ScientistParker[] = { +static const struct TrainerMon sParty_ScientistParker[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_GRIMER, }, { - .iv = 0, .lvl = 29, .species = SPECIES_ELECTRODE, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_ScientistEd[] = { +static const struct TrainerMon sParty_ScientistEd[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_VOLTORB, .moves = {MOVE_SPARK, MOVE_SONIC_BOOM, MOVE_SCREECH, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_TACKLE, MOVE_SMOG}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_MAGNETON, .moves = {MOVE_SPARK, MOVE_THUNDER_WAVE, MOVE_SONIC_BOOM, MOVE_SUPERSONIC}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ScientistTravis[] = { +static const struct TrainerMon sParty_ScientistTravis[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 29, .species = SPECIES_KOFFING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ScientistBraydon[] = { +static const struct TrainerMon sParty_ScientistBraydon[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 33, .species = SPECIES_MAGNETON, }, { - .iv = 0, .lvl = 33, .species = SPECIES_VOLTORB, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ScientistIvan[] = { +static const struct TrainerMon sParty_ScientistIvan[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_MAGNEMITE, }, { - .iv = 0, .lvl = 34, .species = SPECIES_ELECTRODE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BossGiovanni[] = { +static const struct TrainerMon sParty_BossGiovanni[] = { { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 25, .species = SPECIES_ONIX, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 24, .species = SPECIES_RHYHORN, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 29, .species = SPECIES_KANGASKHAN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BossGiovanni2[] = { +static const struct TrainerMon sParty_BossGiovanni2[] = { { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 37, .species = SPECIES_NIDORINO, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 35, .species = SPECIES_KANGASKHAN, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 37, .species = SPECIES_RHYHORN, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 41, .species = SPECIES_NIDOQUEEN, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_LeaderGiovanni[] = { +static const struct TrainerMon sParty_LeaderGiovanni[] = { { - .iv = 0, .lvl = 45, .species = SPECIES_RHYHORN, .moves = {MOVE_TAKE_DOWN, MOVE_ROCK_BLAST, MOVE_SCARY_FACE, MOVE_EARTHQUAKE}, }, { - .iv = 0, .lvl = 42, .species = SPECIES_DUGTRIO, .moves = {MOVE_SLASH, MOVE_SAND_TOMB, MOVE_MUD_SLAP, MOVE_EARTHQUAKE}, }, { - .iv = 0, .lvl = 44, .species = SPECIES_NIDOQUEEN, .moves = {MOVE_BODY_SLAM, MOVE_DOUBLE_KICK, MOVE_POISON_STING, MOVE_EARTHQUAKE}, }, { - .iv = 0, .lvl = 45, .species = SPECIES_NIDOKING, .moves = {MOVE_THRASH, MOVE_DOUBLE_KICK, MOVE_POISON_STING, MOVE_EARTHQUAKE}, }, { - .iv = 0, .lvl = 50, .species = SPECIES_RHYHORN, .moves = {MOVE_TAKE_DOWN, MOVE_ROCK_BLAST, MOVE_SCARY_FACE, MOVE_EARTHQUAKE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt[] = { +static const struct TrainerMon sParty_TeamRocketGrunt[] = { { - .iv = 0, .lvl = 13, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 13, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt2[] = { +static const struct TrainerMon sParty_TeamRocketGrunt2[] = { { - .iv = 0, .lvl = 11, .species = SPECIES_SANDSHREW, }, { - .iv = 0, .lvl = 11, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 11, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt3[] = { +static const struct TrainerMon sParty_TeamRocketGrunt3[] = { { - .iv = 0, .lvl = 11, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 11, .species = SPECIES_EKANS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt4[] = { +static const struct TrainerMon sParty_TeamRocketGrunt4[] = { { - .iv = 0, .lvl = 13, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 13, .species = SPECIES_SANDSHREW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt5[] = { +static const struct TrainerMon sParty_TeamRocketGrunt5[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 17, .species = SPECIES_DROWZEE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt6[] = { +static const struct TrainerMon sParty_TeamRocketGrunt6[] = { { - .iv = 0, .lvl = 15, .species = SPECIES_EKANS, }, { - .iv = 0, .lvl = 15, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt7[] = { +static const struct TrainerMon sParty_TeamRocketGrunt7[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 20, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt8[] = { +static const struct TrainerMon sParty_TeamRocketGrunt8[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 21, .species = SPECIES_MACHOP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt9[] = { +static const struct TrainerMon sParty_TeamRocketGrunt9[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 21, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_TeamRocketGrunt10[] = { +static const struct TrainerMon sParty_TeamRocketGrunt10[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_GRIMER, .moves = {MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE, MOVE_HARDEN}, }, { - .iv = 0, .lvl = 20, .species = SPECIES_KOFFING, .moves = {MOVE_SMOG, MOVE_TACKLE, MOVE_POISON_GAS, MOVE_NONE}, }, { - .iv = 0, .lvl = 20, .species = SPECIES_KOFFING, .moves = {MOVE_SMOG, MOVE_TACKLE, MOVE_POISON_GAS, MOVE_NONE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt11[] = { +static const struct TrainerMon sParty_TeamRocketGrunt11[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 19, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 19, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 19, .species = SPECIES_RATTATA, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_TeamRocketGrunt12[] = { +static const struct TrainerMon sParty_TeamRocketGrunt12[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GRIMER, .moves = {MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE, MOVE_HARDEN}, }, { - .iv = 0, .lvl = 22, .species = SPECIES_KOFFING, .moves = {MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE, MOVE_POISON_GAS}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_TeamRocketGrunt13[] = { +static const struct TrainerMon sParty_TeamRocketGrunt13[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_ZUBAT, .moves = {MOVE_BITE, MOVE_ASTONISH, MOVE_SUPERSONIC, MOVE_LEECH_LIFE}, }, { - .iv = 0, .lvl = 17, .species = SPECIES_KOFFING, .moves = {MOVE_SMOG, MOVE_TACKLE, MOVE_POISON_GAS, MOVE_NONE}, }, { - .iv = 0, .lvl = 17, .species = SPECIES_GRIMER, .moves = {MOVE_SLUDGE, MOVE_DISABLE, MOVE_HARDEN, MOVE_POUND}, }, { - .iv = 0, .lvl = 17, .species = SPECIES_ZUBAT, .moves = {MOVE_BITE, MOVE_ASTONISH, MOVE_SUPERSONIC, MOVE_LEECH_LIFE}, }, { - .iv = 0, .lvl = 17, .species = SPECIES_RATICATE, .moves = {MOVE_HYPER_FANG, MOVE_QUICK_ATTACK, MOVE_TAIL_WHIP, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt14[] = { +static const struct TrainerMon sParty_TeamRocketGrunt14[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 20, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 20, .species = SPECIES_DROWZEE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt15[] = { +static const struct TrainerMon sParty_TeamRocketGrunt15[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 21, .species = SPECIES_MACHOP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt16[] = { +static const struct TrainerMon sParty_TeamRocketGrunt16[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_SANDSHREW, }, { - .iv = 0, .lvl = 23, .species = SPECIES_EKANS, }, { - .iv = 0, .lvl = 23, .species = SPECIES_SANDSLASH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt17[] = { +static const struct TrainerMon sParty_TeamRocketGrunt17[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_EKANS, }, { - .iv = 0, .lvl = 23, .species = SPECIES_SANDSHREW, }, { - .iv = 0, .lvl = 23, .species = SPECIES_ARBOK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt18[] = { +static const struct TrainerMon sParty_TeamRocketGrunt18[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_KOFFING, }, { - .iv = 0, .lvl = 21, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt19[] = { +static const struct TrainerMon sParty_TeamRocketGrunt19[] = { { - .iv = 0, .lvl = 25, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 25, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 25, .species = SPECIES_GOLBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt20[] = { +static const struct TrainerMon sParty_TeamRocketGrunt20[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_KOFFING, }, { - .iv = 0, .lvl = 26, .species = SPECIES_DROWZEE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt21[] = { +static const struct TrainerMon sParty_TeamRocketGrunt21[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 23, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 23, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 23, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt22[] = { +static const struct TrainerMon sParty_TeamRocketGrunt22[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 26, .species = SPECIES_KOFFING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt23[] = { +static const struct TrainerMon sParty_TeamRocketGrunt23[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_CUBONE, }, { - .iv = 0, .lvl = 29, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt24[] = { +static const struct TrainerMon sParty_TeamRocketGrunt24[] = { { - .iv = 0, .lvl = 25, .species = SPECIES_GOLBAT, }, { - .iv = 0, .lvl = 25, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 25, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 25, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 25, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt25[] = { +static const struct TrainerMon sParty_TeamRocketGrunt25[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 28, .species = SPECIES_HYPNO, }, { - .iv = 0, .lvl = 28, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt26[] = { +static const struct TrainerMon sParty_TeamRocketGrunt26[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 29, .species = SPECIES_DROWZEE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt27[] = { +static const struct TrainerMon sParty_TeamRocketGrunt27[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_EKANS, }, { - .iv = 0, .lvl = 28, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 28, .species = SPECIES_CUBONE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt28[] = { +static const struct TrainerMon sParty_TeamRocketGrunt28[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_ARBOK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt29[] = { +static const struct TrainerMon sParty_TeamRocketGrunt29[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_HYPNO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt30[] = { +static const struct TrainerMon sParty_TeamRocketGrunt30[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 29, .species = SPECIES_MACHOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt31[] = { +static const struct TrainerMon sParty_TeamRocketGrunt31[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 28, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 28, .species = SPECIES_GOLBAT, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_TeamRocketGrunt32[] = { +static const struct TrainerMon sParty_TeamRocketGrunt32[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_RATICATE, .moves = {MOVE_SCARY_FACE, MOVE_HYPER_FANG, MOVE_QUICK_ATTACK, MOVE_TAIL_WHIP}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_ARBOK, .moves = {MOVE_GLARE, MOVE_BITE, MOVE_POISON_STING, MOVE_LEER}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 26, .species = SPECIES_GOLBAT, .moves = {MOVE_WING_ATTACK, MOVE_BITE, MOVE_ASTONISH, MOVE_SUPERSONIC}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt33[] = { +static const struct TrainerMon sParty_TeamRocketGrunt33[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_CUBONE, }, { - .iv = 0, .lvl = 29, .species = SPECIES_CUBONE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt34[] = { +static const struct TrainerMon sParty_TeamRocketGrunt34[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_SANDSHREW, }, { - .iv = 0, .lvl = 29, .species = SPECIES_SANDSLASH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt35[] = { +static const struct TrainerMon sParty_TeamRocketGrunt35[] = { { - .iv = 0, .lvl = 26, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 26, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 26, .species = SPECIES_GOLBAT, }, { - .iv = 0, .lvl = 26, .species = SPECIES_RATTATA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt36[] = { +static const struct TrainerMon sParty_TeamRocketGrunt36[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_WEEZING, }, { - .iv = 0, .lvl = 28, .species = SPECIES_GOLBAT, }, { - .iv = 0, .lvl = 28, .species = SPECIES_KOFFING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt37[] = { +static const struct TrainerMon sParty_TeamRocketGrunt37[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 28, .species = SPECIES_GRIMER, }, { - .iv = 0, .lvl = 28, .species = SPECIES_MACHOP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt38[] = { +static const struct TrainerMon sParty_TeamRocketGrunt38[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_GOLBAT, }, { - .iv = 0, .lvl = 28, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 28, .species = SPECIES_HYPNO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt39[] = { +static const struct TrainerMon sParty_TeamRocketGrunt39[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_MACHOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt40[] = { +static const struct TrainerMon sParty_TeamRocketGrunt40[] = { { - .iv = 0, .lvl = 25, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 25, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 25, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 25, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 25, .species = SPECIES_EKANS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt41[] = { +static const struct TrainerMon sParty_TeamRocketGrunt41[] = { { - .iv = 0, .lvl = 32, .species = SPECIES_CUBONE, }, { - .iv = 0, .lvl = 32, .species = SPECIES_DROWZEE, }, { - .iv = 0, .lvl = 32, .species = SPECIES_MAROWAK, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerSamuel[] = { +static const struct TrainerMon sParty_CooltrainerSamuel[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_SANDSLASH, .moves = {MOVE_SLASH, MOVE_SWIFT, MOVE_SAND_ATTACK, MOVE_POISON_STING}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_SANDSLASH, .moves = {MOVE_SLASH, MOVE_SWIFT, MOVE_SAND_ATTACK, MOVE_POISON_STING}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_RHYHORN, .moves = {MOVE_TAKE_DOWN, MOVE_ROCK_BLAST, MOVE_FURY_ATTACK, MOVE_SCARY_FACE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 39, .species = SPECIES_NIDORINO, .moves = {MOVE_FURY_ATTACK, MOVE_HORN_ATTACK, MOVE_POISON_STING, MOVE_DOUBLE_KICK}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 39, .species = SPECIES_NIDOKING, .moves = {MOVE_THRASH, MOVE_DOUBLE_KICK, MOVE_POISON_STING, MOVE_FOCUS_ENERGY}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerGeorge[] = { +static const struct TrainerMon sParty_CooltrainerGeorge[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_EXEGGUTOR, .moves = {MOVE_EGG_BOMB, MOVE_CONFUSION, MOVE_STUN_SPORE, MOVE_SLEEP_POWDER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_SANDSLASH, .moves = {MOVE_FURY_SWIPES, MOVE_SWIFT, MOVE_POISON_STING, MOVE_SAND_ATTACK}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_CLOYSTER, .moves = {MOVE_SPIKE_CANNON, MOVE_SPIKES, MOVE_AURORA_BEAM, MOVE_SUPERSONIC}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_ELECTRODE, .moves = {MOVE_SPARK, MOVE_SONIC_BOOM, MOVE_SCREECH, MOVE_LIGHT_SCREEN}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_ARCANINE, .moves = {MOVE_FLAME_WHEEL, MOVE_ROAR, MOVE_BITE, MOVE_TAKE_DOWN}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerColby[] = { +static const struct TrainerMon sParty_CooltrainerColby[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 41, .species = SPECIES_KINGLER, .moves = {MOVE_GUILLOTINE, MOVE_STOMP, MOVE_MUD_SHOT, MOVE_BUBBLE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_POLIWHIRL, .moves = {MOVE_BODY_SLAM, MOVE_DOUBLE_SLAP, MOVE_WATER_GUN, MOVE_HYPNOSIS}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_TENTACRUEL, .moves = {MOVE_BARRIER, MOVE_WRAP, MOVE_BUBBLE_BEAM, MOVE_ACID}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_SEADRA, .moves = {MOVE_WATER_GUN, MOVE_SMOKESCREEN, MOVE_TWISTER, MOVE_LEER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 43, .species = SPECIES_BLASTOISE, .moves = {MOVE_WATER_GUN, MOVE_BITE, MOVE_RAPID_SPIN, MOVE_RAIN_DANCE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerPaul[] = { +static const struct TrainerMon sParty_CooltrainerPaul[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_SLOWPOKE, .moves = {MOVE_HEADBUTT, MOVE_CONFUSION, MOVE_WATER_GUN, MOVE_DISABLE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_SHELLDER, .moves = {MOVE_AURORA_BEAM, MOVE_CLAMP, MOVE_SUPERSONIC, MOVE_LEER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_KINGLER, .moves = {MOVE_GUILLOTINE, MOVE_STOMP, MOVE_MUD_SHOT, MOVE_BUBBLE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_STARMIE, .moves = {MOVE_BUBBLE_BEAM, MOVE_SWIFT, MOVE_RECOVER, MOVE_RAPID_SPIN}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_GOLDUCK, .moves = {MOVE_CONFUSION, MOVE_SCRATCH, MOVE_SCREECH, MOVE_DISABLE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerRolando[] = { +static const struct TrainerMon sParty_CooltrainerRolando[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_RATICATE, .moves = {MOVE_SUPER_FANG, MOVE_PURSUIT, MOVE_SCARY_FACE, MOVE_QUICK_ATTACK}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_IVYSAUR, .moves = {MOVE_RAZOR_LEAF, MOVE_SLEEP_POWDER, MOVE_SWEET_SCENT, MOVE_SYNTHESIS}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_WARTORTLE, .moves = {MOVE_WATER_GUN, MOVE_BITE, MOVE_RAPID_SPIN, MOVE_TAIL_WHIP}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_CHARMELEON, .moves = {MOVE_FLAMETHROWER, MOVE_SLASH, MOVE_SMOKESCREEN, MOVE_SCARY_FACE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_CHARIZARD, .moves = {MOVE_FLAMETHROWER, MOVE_WING_ATTACK, MOVE_SMOKESCREEN, MOVE_SCARY_FACE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerGilbert[] = { +static const struct TrainerMon sParty_CooltrainerGilbert[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PIDGEOTTO, .moves = {MOVE_WING_ATTACK, MOVE_FEATHER_DANCE, MOVE_WHIRLWIND, MOVE_QUICK_ATTACK}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_FEAROW, .moves = {MOVE_DRILL_PECK, MOVE_MIRROR_MOVE, MOVE_PURSUIT, MOVE_LEER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PERSIAN, .moves = {MOVE_PAY_DAY, MOVE_FAINT_ATTACK, MOVE_SCREECH, MOVE_BITE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_LICKITUNG, .moves = {MOVE_SLAM, MOVE_DISABLE, MOVE_WRAP, MOVE_SUPERSONIC}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_TAUROS, .moves = {MOVE_HORN_ATTACK, MOVE_SCARY_FACE, MOVE_SWAGGER, MOVE_TAIL_WHIP}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerOwen[] = { +static const struct TrainerMon sParty_CooltrainerOwen[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_NIDORINO, .moves = {MOVE_SCRATCH, MOVE_POISON_STING, MOVE_DOUBLE_KICK, MOVE_BITE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_NIDORINA, .moves = {MOVE_HORN_ATTACK, MOVE_POISON_STING, MOVE_DOUBLE_KICK, MOVE_LEER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_RATICATE, .moves = {MOVE_SUPER_FANG, MOVE_PURSUIT, MOVE_SCARY_FACE, MOVE_QUICK_ATTACK}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_SANDSLASH, .moves = {MOVE_FURY_SWIPES, MOVE_SWIFT, MOVE_SLASH, MOVE_POISON_STING}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_RHYHORN, .moves = {MOVE_ROCK_BLAST, MOVE_SCARY_FACE, MOVE_STOMP, MOVE_TAIL_WHIP}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerBerke[] = { +static const struct TrainerMon sParty_CooltrainerBerke[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_SEEL, .moves = {MOVE_TAKE_DOWN, MOVE_AURORA_BEAM, MOVE_ICY_WIND, MOVE_GROWL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_GRAVELER, .moves = {MOVE_ROCK_BLAST, MOVE_MAGNITUDE, MOVE_ROCK_THROW, MOVE_MUD_SPORT}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_KINGLER, .moves = {MOVE_GUILLOTINE, MOVE_STOMP, MOVE_MUD_SHOT, MOVE_BUBBLE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_ONIX, .moves = {MOVE_SLAM, MOVE_SANDSTORM, MOVE_DRAGON_BREATH, MOVE_ROCK_THROW}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_CLOYSTER, .moves = {MOVE_SPIKE_CANNON, MOVE_AURORA_BEAM, MOVE_SUPERSONIC, MOVE_PROTECT}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerYuji[] = { +static const struct TrainerMon sParty_CooltrainerYuji[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_SANDSLASH, .moves = {MOVE_SLASH, MOVE_SWIFT, MOVE_SAND_ATTACK, MOVE_POISON_STING}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_GRAVELER, .moves = {MOVE_ROCK_BLAST, MOVE_MAGNITUDE, MOVE_MUD_SPORT, MOVE_DEFENSE_CURL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_ONIX, .moves = {MOVE_DRAGON_BREATH, MOVE_SANDSTORM, MOVE_ROCK_THROW, MOVE_BIND}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_GRAVELER, .moves = {MOVE_ROCK_BLAST, MOVE_MAGNITUDE, MOVE_ROLLOUT, MOVE_DEFENSE_CURL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_MAROWAK, .moves = {MOVE_BONEMERANG, MOVE_HEADBUTT, MOVE_LEER, MOVE_GROWL}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerWarren[] = { +static const struct TrainerMon sParty_CooltrainerWarren[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_MAROWAK, .moves = {MOVE_BONEMERANG, MOVE_HEADBUTT, MOVE_LEER, MOVE_GROWL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_MAROWAK, .moves = {MOVE_BONEMERANG, MOVE_HEADBUTT, MOVE_LEER, MOVE_GROWL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_RHYHORN, .moves = {MOVE_TAKE_DOWN, MOVE_ROCK_BLAST, MOVE_FURY_ATTACK, MOVE_SCARY_FACE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 39, .species = SPECIES_NIDORINA, .moves = {MOVE_FURY_SWIPES, MOVE_BITE, MOVE_POISON_STING, MOVE_DOUBLE_KICK}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 39, .species = SPECIES_NIDOQUEEN, .moves = {MOVE_BODY_SLAM, MOVE_BITE, MOVE_POISON_STING, MOVE_DOUBLE_KICK}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerMary[] = { +static const struct TrainerMon sParty_CooltrainerMary[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 22, .species = SPECIES_BELLSPROUT, .moves = {MOVE_WRAP, MOVE_STUN_SPORE, MOVE_POISON_POWDER, MOVE_GROWTH}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 22, .species = SPECIES_ODDISH, .moves = {MOVE_POISON_POWDER, MOVE_STUN_SPORE, MOVE_ABSORB, MOVE_SWEET_SCENT}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 22, .species = SPECIES_WEEPINBELL, .moves = {MOVE_VINE_WHIP, MOVE_STUN_SPORE, MOVE_POISON_POWDER, MOVE_GROWTH}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 22, .species = SPECIES_GLOOM, .moves = {MOVE_ABSORB, MOVE_STUN_SPORE, MOVE_POISON_POWDER, MOVE_SWEET_SCENT}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 22, .species = SPECIES_IVYSAUR, .moves = {MOVE_RAZOR_LEAF, MOVE_SLEEP_POWDER, MOVE_VINE_WHIP, MOVE_LEECH_SEED}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerCaroline[] = { +static const struct TrainerMon sParty_CooltrainerCaroline[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_BELLSPROUT, .moves = {MOVE_RAZOR_LEAF, MOVE_ACID, MOVE_STUN_SPORE, MOVE_POISON_POWDER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_WEEPINBELL, .moves = {MOVE_RAZOR_LEAF, MOVE_ACID, MOVE_SLEEP_POWDER, MOVE_POISON_POWDER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_VICTREEBEL, .moves = {MOVE_RAZOR_LEAF, MOVE_ACID, MOVE_STUN_SPORE, MOVE_SLEEP_POWDER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PARAS, .moves = {MOVE_GROWTH, MOVE_SLASH, MOVE_LEECH_LIFE, MOVE_STUN_SPORE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PARASECT, .moves = {MOVE_SPORE, MOVE_SLASH, MOVE_LEECH_LIFE, MOVE_POISON_POWDER}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerAlexa[] = { +static const struct TrainerMon sParty_CooltrainerAlexa[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_CLEFAIRY, .moves = {MOVE_LIGHT_SCREEN, MOVE_COSMIC_POWER, MOVE_DOUBLE_SLAP, MOVE_ENCORE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_JIGGLYPUFF, .moves = {MOVE_SING, MOVE_BODY_SLAM, MOVE_ROLLOUT, MOVE_DISABLE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PERSIAN, .moves = {MOVE_PAY_DAY, MOVE_FAINT_ATTACK, MOVE_BITE, MOVE_SCREECH}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_DEWGONG, .moves = {MOVE_SHEER_COLD, MOVE_TAKE_DOWN, MOVE_REST, MOVE_AURORA_BEAM}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_CHANSEY, .moves = {MOVE_SING, MOVE_EGG_BOMB, MOVE_SOFT_BOILED, MOVE_MINIMIZE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerShannon[] = { +static const struct TrainerMon sParty_CooltrainerShannon[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_BEEDRILL, .moves = {MOVE_PIN_MISSILE, MOVE_TWINEEDLE, MOVE_AGILITY, MOVE_PURSUIT}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_BUTTERFREE, .moves = {MOVE_SAFEGUARD, MOVE_PSYBEAM, MOVE_GUST, MOVE_SUPERSONIC}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PARASECT, .moves = {MOVE_SPORE, MOVE_LEECH_LIFE, MOVE_SLASH, MOVE_GROWTH}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_VENONAT, .moves = {MOVE_PSYBEAM, MOVE_STUN_SPORE, MOVE_LEECH_LIFE, MOVE_DISABLE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_VENOMOTH, .moves = {MOVE_PSYBEAM, MOVE_GUST, MOVE_SUPERSONIC, MOVE_LEECH_LIFE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerNaomi[] = { +static const struct TrainerMon sParty_CooltrainerNaomi[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PERSIAN, .moves = {MOVE_FURY_SWIPES, MOVE_SCREECH, MOVE_FAINT_ATTACK, MOVE_PAY_DAY}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PONYTA, .moves = {MOVE_AGILITY, MOVE_TAKE_DOWN, MOVE_FIRE_SPIN, MOVE_STOMP}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_RAPIDASH, .moves = {MOVE_FURY_ATTACK, MOVE_FIRE_SPIN, MOVE_STOMP, MOVE_GROWL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_VULPIX, .moves = {MOVE_FLAMETHROWER, MOVE_CONFUSE_RAY, MOVE_QUICK_ATTACK, MOVE_IMPRISON}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_NINETALES, .moves = {MOVE_SAFEGUARD, MOVE_WILL_O_WISP, MOVE_CONFUSE_RAY, MOVE_FIRE_SPIN}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerBrooke[] = { +static const struct TrainerMon sParty_CooltrainerBrooke[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_TANGELA, .moves = {MOVE_SLAM, MOVE_BIND, MOVE_MEGA_DRAIN, MOVE_INGRAIN}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_GLOOM, .moves = {MOVE_ACID, MOVE_MOONLIGHT, MOVE_SLEEP_POWDER, MOVE_STUN_SPORE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_VILEPLUME, .moves = {MOVE_MEGA_DRAIN, MOVE_ACID, MOVE_STUN_SPORE, MOVE_AROMATHERAPY}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_IVYSAUR, .moves = {MOVE_RAZOR_LEAF, MOVE_SWEET_SCENT, MOVE_GROWL, MOVE_LEECH_SEED}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_VENUSAUR, .moves = {MOVE_RAZOR_LEAF, MOVE_GROWTH, MOVE_SLEEP_POWDER, MOVE_POISON_POWDER}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerAustina[] = { +static const struct TrainerMon sParty_CooltrainerAustina[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_RHYHORN, .moves = {MOVE_HORN_DRILL, MOVE_ROCK_BLAST, MOVE_SCARY_FACE, MOVE_STOMP}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_NIDORINA, .moves = {MOVE_DOUBLE_KICK, MOVE_FURY_SWIPES, MOVE_BITE, MOVE_FLATTER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_NIDOQUEEN, .moves = {MOVE_BODY_SLAM, MOVE_DOUBLE_KICK, MOVE_BITE, MOVE_GROWL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_NIDORINO, .moves = {MOVE_HORN_ATTACK, MOVE_POISON_STING, MOVE_FOCUS_ENERGY, MOVE_LEER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_NIDOKING, .moves = {MOVE_THRASH, MOVE_DOUBLE_KICK, MOVE_POISON_STING, MOVE_PECK}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerJulie[] = { +static const struct TrainerMon sParty_CooltrainerJulie[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PERSIAN, .moves = {MOVE_FURY_SWIPES, MOVE_BITE, MOVE_SCREECH, MOVE_FAINT_ATTACK}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_NINETALES, .moves = {MOVE_FLAMETHROWER, MOVE_WILL_O_WISP, MOVE_CONFUSE_RAY, MOVE_GRUDGE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_RAPIDASH, .moves = {MOVE_FURY_ATTACK, MOVE_FIRE_SPIN, MOVE_TAKE_DOWN, MOVE_AGILITY}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_PIKACHU, .moves = {MOVE_THUNDERBOLT, MOVE_THUNDER_WAVE, MOVE_DOUBLE_TEAM, MOVE_QUICK_ATTACK}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 42, .species = SPECIES_RAICHU, .moves = {MOVE_THUNDER, MOVE_THUNDER_WAVE, MOVE_SLAM, MOVE_DOUBLE_TEAM}, }, }; -static const struct TrainerMonItemCustomMoves sParty_EliteFourLorelei[] = { +static const struct TrainerMon sParty_EliteFourLorelei[] = { { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 52, .species = SPECIES_DEWGONG, .heldItem = ITEM_NONE, .moves = {MOVE_ICE_BEAM, MOVE_SURF, MOVE_HAIL, MOVE_SAFEGUARD}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 51, .species = SPECIES_CLOYSTER, .heldItem = ITEM_NONE, .moves = {MOVE_SPIKES, MOVE_PROTECT, MOVE_HAIL, MOVE_DIVE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 52, .species = SPECIES_SLOWBRO, .heldItem = ITEM_NONE, .moves = {MOVE_ICE_BEAM, MOVE_SURF, MOVE_AMNESIA, MOVE_YAWN}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 54, .species = SPECIES_JYNX, .heldItem = ITEM_NONE, .moves = {MOVE_ICE_PUNCH, MOVE_DOUBLE_SLAP, MOVE_LOVELY_KISS, MOVE_ATTRACT}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 54, .species = SPECIES_LAPRAS, .heldItem = ITEM_SITRUS_BERRY, @@ -5487,37 +4835,37 @@ static const struct TrainerMonItemCustomMoves sParty_EliteFourLorelei[] = { }, }; -static const struct TrainerMonItemCustomMoves sParty_EliteFourBruno[] = { +static const struct TrainerMon sParty_EliteFourBruno[] = { { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 51, .species = SPECIES_ONIX, .heldItem = ITEM_NONE, .moves = {MOVE_EARTHQUAKE, MOVE_ROCK_TOMB, MOVE_IRON_TAIL, MOVE_ROAR}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 53, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_NONE, .moves = {MOVE_SKY_UPPERCUT, MOVE_MACH_PUNCH, MOVE_ROCK_TOMB, MOVE_COUNTER}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 53, .species = SPECIES_HITMONLEE, .heldItem = ITEM_NONE, .moves = {MOVE_MEGA_KICK, MOVE_FORESIGHT, MOVE_BRICK_BREAK, MOVE_FACADE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 54, .species = SPECIES_ONIX, .heldItem = ITEM_NONE, .moves = {MOVE_DOUBLE_EDGE, MOVE_EARTHQUAKE, MOVE_IRON_TAIL, MOVE_SAND_TOMB}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 56, .species = SPECIES_MACHAMP, .heldItem = ITEM_SITRUS_BERRY, @@ -5525,37 +4873,37 @@ static const struct TrainerMonItemCustomMoves sParty_EliteFourBruno[] = { }, }; -static const struct TrainerMonItemCustomMoves sParty_EliteFourAgatha[] = { +static const struct TrainerMon sParty_EliteFourAgatha[] = { { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 54, .species = SPECIES_GENGAR, .heldItem = ITEM_NONE, .moves = {MOVE_SHADOW_PUNCH, MOVE_CONFUSE_RAY, MOVE_TOXIC, MOVE_DOUBLE_TEAM}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 54, .species = SPECIES_GOLBAT, .heldItem = ITEM_NONE, .moves = {MOVE_CONFUSE_RAY, MOVE_POISON_FANG, MOVE_AIR_CUTTER, MOVE_BITE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 53, .species = SPECIES_HAUNTER, .heldItem = ITEM_NONE, .moves = {MOVE_HYPNOSIS, MOVE_DREAM_EATER, MOVE_CURSE, MOVE_MEAN_LOOK}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 56, .species = SPECIES_ARBOK, .heldItem = ITEM_NONE, .moves = {MOVE_SLUDGE_BOMB, MOVE_SCREECH, MOVE_IRON_TAIL, MOVE_BITE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 58, .species = SPECIES_GENGAR, .heldItem = ITEM_SITRUS_BERRY, @@ -5563,37 +4911,37 @@ static const struct TrainerMonItemCustomMoves sParty_EliteFourAgatha[] = { }, }; -static const struct TrainerMonItemCustomMoves sParty_EliteFourLance[] = { +static const struct TrainerMon sParty_EliteFourLance[] = { { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 56, .species = SPECIES_GYARADOS, .heldItem = ITEM_NONE, .moves = {MOVE_HYPER_BEAM, MOVE_DRAGON_RAGE, MOVE_TWISTER, MOVE_BITE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 54, .species = SPECIES_DRAGONAIR, .heldItem = ITEM_NONE, .moves = {MOVE_HYPER_BEAM, MOVE_SAFEGUARD, MOVE_DRAGON_RAGE, MOVE_OUTRAGE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 54, .species = SPECIES_DRAGONAIR, .heldItem = ITEM_NONE, .moves = {MOVE_HYPER_BEAM, MOVE_SAFEGUARD, MOVE_THUNDER_WAVE, MOVE_OUTRAGE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 58, .species = SPECIES_AERODACTYL, .heldItem = ITEM_NONE, .moves = {MOVE_HYPER_BEAM, MOVE_ANCIENT_POWER, MOVE_WING_ATTACK, MOVE_SCARY_FACE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 60, .species = SPECIES_DRAGONITE, .heldItem = ITEM_SITRUS_BERRY, @@ -5601,606 +4949,576 @@ static const struct TrainerMonItemCustomMoves sParty_EliteFourLance[] = { }, }; -static const struct TrainerMonNoItemCustomMoves sParty_LeaderBrock[] = { +static const struct TrainerMon sParty_LeaderBrock[] = { { - .iv = 0, .lvl = 12, .species = SPECIES_GEODUDE, .moves = {MOVE_TACKLE, MOVE_DEFENSE_CURL, MOVE_NONE, MOVE_NONE}, }, { - .iv = 0, .lvl = 14, .species = SPECIES_ONIX, .moves = {MOVE_TACKLE, MOVE_BIND, MOVE_ROCK_TOMB, MOVE_NONE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_LeaderMisty[] = { +static const struct TrainerMon sParty_LeaderMisty[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_STARYU, .moves = {MOVE_TACKLE, MOVE_HARDEN, MOVE_RECOVER, MOVE_WATER_PULSE}, }, { - .iv = 0, .lvl = 21, .species = SPECIES_STARMIE, .moves = {MOVE_SWIFT, MOVE_RECOVER, MOVE_RAPID_SPIN, MOVE_WATER_PULSE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_LeaderLtSurge[] = { +static const struct TrainerMon sParty_LeaderLtSurge[] = { { - .iv = 0, .lvl = 21, .species = SPECIES_VOLTORB, .moves = {MOVE_SONIC_BOOM, MOVE_TACKLE, MOVE_SCREECH, MOVE_SHOCK_WAVE}, }, { - .iv = 0, .lvl = 18, .species = SPECIES_PIKACHU, .moves = {MOVE_QUICK_ATTACK, MOVE_THUNDER_WAVE, MOVE_DOUBLE_TEAM, MOVE_SHOCK_WAVE}, }, { - .iv = 0, .lvl = 24, .species = SPECIES_RAICHU, .moves = {MOVE_QUICK_ATTACK, MOVE_THUNDER_WAVE, MOVE_DOUBLE_TEAM, MOVE_SHOCK_WAVE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_LeaderErika[] = { +static const struct TrainerMon sParty_LeaderErika[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_VICTREEBEL, .moves = {MOVE_STUN_SPORE, MOVE_ACID, MOVE_POISON_POWDER, MOVE_GIGA_DRAIN}, }, { - .iv = 0, .lvl = 24, .species = SPECIES_TANGELA, .moves = {MOVE_POISON_POWDER, MOVE_CONSTRICT, MOVE_INGRAIN, MOVE_GIGA_DRAIN}, }, { - .iv = 0, .lvl = 29, .species = SPECIES_VILEPLUME, .moves = {MOVE_SLEEP_POWDER, MOVE_ACID, MOVE_STUN_SPORE, MOVE_GIGA_DRAIN}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_LeaderKoga[] = { +static const struct TrainerMon sParty_LeaderKoga[] = { { - .iv = 0, .lvl = 37, .species = SPECIES_KOFFING, .moves = {MOVE_SELF_DESTRUCT, MOVE_SLUDGE, MOVE_SMOKESCREEN, MOVE_TOXIC}, }, { - .iv = 0, .lvl = 39, .species = SPECIES_MUK, .moves = {MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_ACID_ARMOR, MOVE_TOXIC}, }, { - .iv = 0, .lvl = 37, .species = SPECIES_KOFFING, .moves = {MOVE_SELF_DESTRUCT, MOVE_SLUDGE, MOVE_SMOKESCREEN, MOVE_TOXIC}, }, { - .iv = 0, .lvl = 43, .species = SPECIES_WEEZING, .moves = {MOVE_TACKLE, MOVE_SLUDGE, MOVE_SMOKESCREEN, MOVE_TOXIC}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_LeaderBlaine[] = { +static const struct TrainerMon sParty_LeaderBlaine[] = { { - .iv = 0, .lvl = 42, .species = SPECIES_GROWLITHE, .moves = {MOVE_BITE, MOVE_ROAR, MOVE_TAKE_DOWN, MOVE_FIRE_BLAST}, }, { - .iv = 0, .lvl = 40, .species = SPECIES_PONYTA, .moves = {MOVE_STOMP, MOVE_BOUNCE, MOVE_FIRE_SPIN, MOVE_FIRE_BLAST}, }, { - .iv = 0, .lvl = 42, .species = SPECIES_RAPIDASH, .moves = {MOVE_STOMP, MOVE_BOUNCE, MOVE_FIRE_SPIN, MOVE_FIRE_BLAST}, }, { - .iv = 0, .lvl = 47, .species = SPECIES_ARCANINE, .moves = {MOVE_BITE, MOVE_ROAR, MOVE_TAKE_DOWN, MOVE_FIRE_BLAST}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_LeaderSabrina[] = { +static const struct TrainerMon sParty_LeaderSabrina[] = { { - .iv = 0, .lvl = 38, .species = SPECIES_KADABRA, .moves = {MOVE_PSYBEAM, MOVE_REFLECT, MOVE_FUTURE_SIGHT, MOVE_CALM_MIND}, }, { - .iv = 0, .lvl = 37, .species = SPECIES_MR_MIME, .moves = {MOVE_BARRIER, MOVE_PSYBEAM, MOVE_BATON_PASS, MOVE_CALM_MIND}, }, { - .iv = 0, .lvl = 38, .species = SPECIES_VENOMOTH, .moves = {MOVE_PSYBEAM, MOVE_GUST, MOVE_LEECH_LIFE, MOVE_SUPERSONIC}, }, { - .iv = 0, .lvl = 43, .species = SPECIES_ALAKAZAM, .moves = {MOVE_PSYCHIC, MOVE_RECOVER, MOVE_FUTURE_SIGHT, MOVE_CALM_MIND}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GentlemanThomas[] = { +static const struct TrainerMon sParty_GentlemanThomas[] = { { - .iv = 0, .lvl = 18, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 18, .species = SPECIES_GROWLITHE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GentlemanArthur[] = { +static const struct TrainerMon sParty_GentlemanArthur[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_NIDORAN_M, }, { - .iv = 0, .lvl = 19, .species = SPECIES_NIDORAN_F, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GentlemanTucker[] = { +static const struct TrainerMon sParty_GentlemanTucker[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_PIKACHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GentlemanNorton[] = { +static const struct TrainerMon sParty_GentlemanNorton[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_PERSIAN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GentlemanWalter[] = { +static const struct TrainerMon sParty_GentlemanWalter[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 17, .species = SPECIES_PONYTA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalSsAnneSquirtle[] = { +static const struct TrainerMon sParty_RivalSsAnneSquirtle[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 19, .species = SPECIES_PIDGEOTTO, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 16, .species = SPECIES_RATICATE, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 18, .species = SPECIES_KADABRA, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 20, .species = SPECIES_WARTORTLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalSsAnneBulbasaur[] = { +static const struct TrainerMon sParty_RivalSsAnneBulbasaur[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 19, .species = SPECIES_PIDGEOTTO, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 16, .species = SPECIES_RATICATE, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 18, .species = SPECIES_KADABRA, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 20, .species = SPECIES_IVYSAUR, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalSsAnneCharmander[] = { +static const struct TrainerMon sParty_RivalSsAnneCharmander[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 19, .species = SPECIES_PIDGEOTTO, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 16, .species = SPECIES_RATICATE, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 18, .species = SPECIES_KADABRA, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 20, .species = SPECIES_CHARMELEON, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalPokemonTowerSquirtle[] = { +static const struct TrainerMon sParty_RivalPokemonTowerSquirtle[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 25, .species = SPECIES_PIDGEOTTO, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 23, .species = SPECIES_GROWLITHE, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 22, .species = SPECIES_EXEGGCUTE, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 20, .species = SPECIES_KADABRA, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 25, .species = SPECIES_WARTORTLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalPokemonTowerBulbasaur[] = { +static const struct TrainerMon sParty_RivalPokemonTowerBulbasaur[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 25, .species = SPECIES_PIDGEOTTO, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 23, .species = SPECIES_GYARADOS, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 22, .species = SPECIES_GROWLITHE, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 20, .species = SPECIES_KADABRA, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 25, .species = SPECIES_IVYSAUR, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalPokemonTowerCharmander[] = { +static const struct TrainerMon sParty_RivalPokemonTowerCharmander[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 25, .species = SPECIES_PIDGEOTTO, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 23, .species = SPECIES_EXEGGCUTE, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 22, .species = SPECIES_GYARADOS, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 20, .species = SPECIES_KADABRA, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 25, .species = SPECIES_CHARMELEON, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalSilphSquirtle[] = { +static const struct TrainerMon sParty_RivalSilphSquirtle[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_PIDGEOT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_GROWLITHE, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 35, .species = SPECIES_EXEGGCUTE, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 35, .species = SPECIES_ALAKAZAM, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 40, .species = SPECIES_BLASTOISE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalSilphBulbasaur[] = { +static const struct TrainerMon sParty_RivalSilphBulbasaur[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_PIDGEOT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_GYARADOS, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 35, .species = SPECIES_GROWLITHE, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 35, .species = SPECIES_ALAKAZAM, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 40, .species = SPECIES_VENUSAUR, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RivalSilphCharmander[] = { +static const struct TrainerMon sParty_RivalSilphCharmander[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_PIDGEOT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_EXEGGCUTE, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 35, .species = SPECIES_GYARADOS, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 35, .species = SPECIES_ALAKAZAM, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 40, .species = SPECIES_CHARIZARD, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RivalRoute22LateSquirtle[] = { +static const struct TrainerMon sParty_RivalRoute22LateSquirtle[] = { { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 47, .species = SPECIES_PIDGEOT, .moves = {MOVE_FEATHER_DANCE, MOVE_WING_ATTACK, MOVE_GUST, MOVE_QUICK_ATTACK}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 45, .species = SPECIES_RHYHORN, .moves = {MOVE_TAKE_DOWN, MOVE_HORN_DRILL, MOVE_ROCK_BLAST, MOVE_FURY_ATTACK}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 45, .species = SPECIES_GROWLITHE, .moves = {MOVE_FLAME_WHEEL, MOVE_TAKE_DOWN, MOVE_LEER, MOVE_AGILITY}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 45, .species = SPECIES_EXEGGCUTE, .moves = {MOVE_SOLAR_BEAM, MOVE_SLEEP_POWDER, MOVE_POISON_POWDER, MOVE_STUN_SPORE}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 47, .species = SPECIES_ALAKAZAM, .moves = {MOVE_PSYCHIC, MOVE_CALM_MIND, MOVE_FUTURE_SIGHT, MOVE_DISABLE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 53, .species = SPECIES_BLASTOISE, .moves = {MOVE_WATER_GUN, MOVE_RAIN_DANCE, MOVE_BITE, MOVE_RAPID_SPIN}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RivalRoute22LateBulbasaur[] = { +static const struct TrainerMon sParty_RivalRoute22LateBulbasaur[] = { { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 47, .species = SPECIES_PIDGEOT, .moves = {MOVE_FEATHER_DANCE, MOVE_WING_ATTACK, MOVE_GUST, MOVE_QUICK_ATTACK}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 45, .species = SPECIES_RHYHORN, .moves = {MOVE_TAKE_DOWN, MOVE_HORN_DRILL, MOVE_ROCK_BLAST, MOVE_FURY_ATTACK}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 45, .species = SPECIES_GYARADOS, .moves = {MOVE_HYDRO_PUMP, MOVE_TWISTER, MOVE_LEER, MOVE_RAIN_DANCE}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 45, .species = SPECIES_GROWLITHE, .moves = {MOVE_FLAME_WHEEL, MOVE_TAKE_DOWN, MOVE_LEER, MOVE_AGILITY}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 47, .species = SPECIES_ALAKAZAM, .moves = {MOVE_PSYCHIC, MOVE_CALM_MIND, MOVE_FUTURE_SIGHT, MOVE_DISABLE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 53, .species = SPECIES_VENUSAUR, .moves = {MOVE_RAZOR_LEAF, MOVE_SWEET_SCENT, MOVE_GROWTH, MOVE_SYNTHESIS}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RivalRoute22LateCharmander[] = { +static const struct TrainerMon sParty_RivalRoute22LateCharmander[] = { { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 47, .species = SPECIES_PIDGEOT, .moves = {MOVE_FEATHER_DANCE, MOVE_WING_ATTACK, MOVE_GUST, MOVE_QUICK_ATTACK}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 45, .species = SPECIES_RHYHORN, .moves = {MOVE_TAKE_DOWN, MOVE_HORN_DRILL, MOVE_ROCK_BLAST, MOVE_FURY_ATTACK}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 45, .species = SPECIES_EXEGGCUTE, .moves = {MOVE_SOLAR_BEAM, MOVE_SLEEP_POWDER, MOVE_POISON_POWDER, MOVE_STUN_SPORE}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 45, .species = SPECIES_GYARADOS, .moves = {MOVE_HYDRO_PUMP, MOVE_TWISTER, MOVE_LEER, MOVE_RAIN_DANCE}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 47, .species = SPECIES_ALAKAZAM, .moves = {MOVE_PSYCHIC, MOVE_CALM_MIND, MOVE_FUTURE_SIGHT, MOVE_DISABLE}, }, { - .iv = 250, + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 53, .species = SPECIES_CHARIZARD, .moves = {MOVE_FLAMETHROWER, MOVE_WING_ATTACK, MOVE_SLASH, MOVE_SCARY_FACE}, }, }; -static const struct TrainerMonItemCustomMoves sParty_ChampionFirstSquirtle[] = { +static const struct TrainerMon sParty_ChampionFirstSquirtle[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 59, .species = SPECIES_PIDGEOT, .heldItem = ITEM_NONE, .moves = {MOVE_AERIAL_ACE, MOVE_FEATHER_DANCE, MOVE_SAND_ATTACK, MOVE_WHIRLWIND}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 57, .species = SPECIES_ALAKAZAM, .heldItem = ITEM_NONE, .moves = {MOVE_PSYCHIC, MOVE_FUTURE_SIGHT, MOVE_RECOVER, MOVE_REFLECT}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 59, .species = SPECIES_RHYDON, .heldItem = ITEM_NONE, .moves = {MOVE_TAKE_DOWN, MOVE_EARTHQUAKE, MOVE_ROCK_TOMB, MOVE_SCARY_FACE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 59, .species = SPECIES_ARCANINE, .heldItem = ITEM_NONE, .moves = {MOVE_EXTREME_SPEED, MOVE_FLAMETHROWER, MOVE_ROAR, MOVE_BITE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 61, .species = SPECIES_EXEGGUTOR, .heldItem = ITEM_NONE, .moves = {MOVE_GIGA_DRAIN, MOVE_EGG_BOMB, MOVE_SLEEP_POWDER, MOVE_LIGHT_SCREEN}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 63, .species = SPECIES_BLASTOISE, .heldItem = ITEM_SITRUS_BERRY, @@ -6208,44 +5526,44 @@ static const struct TrainerMonItemCustomMoves sParty_ChampionFirstSquirtle[] = { }, }; -static const struct TrainerMonItemCustomMoves sParty_ChampionFirstBulbasaur[] = { +static const struct TrainerMon sParty_ChampionFirstBulbasaur[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 59, .species = SPECIES_PIDGEOT, .heldItem = ITEM_NONE, .moves = {MOVE_AERIAL_ACE, MOVE_FEATHER_DANCE, MOVE_SAND_ATTACK, MOVE_WHIRLWIND}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 57, .species = SPECIES_ALAKAZAM, .heldItem = ITEM_NONE, .moves = {MOVE_PSYCHIC, MOVE_FUTURE_SIGHT, MOVE_RECOVER, MOVE_REFLECT}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 59, .species = SPECIES_RHYDON, .heldItem = ITEM_NONE, .moves = {MOVE_TAKE_DOWN, MOVE_EARTHQUAKE, MOVE_ROCK_TOMB, MOVE_SCARY_FACE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 59, .species = SPECIES_GYARADOS, .heldItem = ITEM_NONE, .moves = {MOVE_HYDRO_PUMP, MOVE_DRAGON_RAGE, MOVE_BITE, MOVE_THRASH}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 61, .species = SPECIES_ARCANINE, .heldItem = ITEM_NONE, .moves = {MOVE_EXTREME_SPEED, MOVE_FLAMETHROWER, MOVE_ROAR, MOVE_BITE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 63, .species = SPECIES_VENUSAUR, .heldItem = ITEM_SITRUS_BERRY, @@ -6253,44 +5571,44 @@ static const struct TrainerMonItemCustomMoves sParty_ChampionFirstBulbasaur[] = }, }; -static const struct TrainerMonItemCustomMoves sParty_ChampionFirstCharmander[] = { +static const struct TrainerMon sParty_ChampionFirstCharmander[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 59, .species = SPECIES_PIDGEOT, .heldItem = ITEM_NONE, .moves = {MOVE_AERIAL_ACE, MOVE_FEATHER_DANCE, MOVE_SAND_ATTACK, MOVE_WHIRLWIND}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 57, .species = SPECIES_ALAKAZAM, .heldItem = ITEM_NONE, .moves = {MOVE_PSYCHIC, MOVE_FUTURE_SIGHT, MOVE_RECOVER, MOVE_REFLECT}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 59, .species = SPECIES_RHYDON, .heldItem = ITEM_NONE, .moves = {MOVE_TAKE_DOWN, MOVE_EARTHQUAKE, MOVE_ROCK_TOMB, MOVE_SCARY_FACE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 59, .species = SPECIES_EXEGGUTOR, .heldItem = ITEM_NONE, .moves = {MOVE_GIGA_DRAIN, MOVE_EGG_BOMB, MOVE_SLEEP_POWDER, MOVE_LIGHT_SCREEN}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 61, .species = SPECIES_GYARADOS, .heldItem = ITEM_NONE, .moves = {MOVE_HYDRO_PUMP, MOVE_DRAGON_RAGE, MOVE_BITE, MOVE_THRASH}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 63, .species = SPECIES_CHARIZARD, .heldItem = ITEM_SITRUS_BERRY, @@ -6298,2256 +5616,2023 @@ static const struct TrainerMonItemCustomMoves sParty_ChampionFirstCharmander[] = }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerPatricia[] = { +static const struct TrainerMon sParty_ChannelerPatricia[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerCarly[] = { +static const struct TrainerMon sParty_ChannelerCarly[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerHope[] = { +static const struct TrainerMon sParty_ChannelerHope[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerPaula[] = { +static const struct TrainerMon sParty_ChannelerPaula[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerLaurel[] = { +static const struct TrainerMon sParty_ChannelerLaurel[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_GASTLY, }, { - .iv = 0, .lvl = 23, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerJody[] = { +static const struct TrainerMon sParty_ChannelerJody[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerTammy[] = { +static const struct TrainerMon sParty_ChannelerTammy[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_HAUNTER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerRuth[] = { +static const struct TrainerMon sParty_ChannelerRuth[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerKarina[] = { +static const struct TrainerMon sParty_ChannelerKarina[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerJanae[] = { +static const struct TrainerMon sParty_ChannelerJanae[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerAngelica[] = { +static const struct TrainerMon sParty_ChannelerAngelica[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerEmilia[] = { +static const struct TrainerMon sParty_ChannelerEmilia[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerJennifer[] = { +static const struct TrainerMon sParty_ChannelerJennifer[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Channeler1[] = { +static const struct TrainerMon sParty_Channeler1[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_HAUNTER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Channeler2[] = { +static const struct TrainerMon sParty_Channeler2[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Channeler3[] = { +static const struct TrainerMon sParty_Channeler3[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Channeler4[] = { +static const struct TrainerMon sParty_Channeler4[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Channeler5[] = { +static const struct TrainerMon sParty_Channeler5[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_HAUNTER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Channeler6[] = { +static const struct TrainerMon sParty_Channeler6[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, { - .iv = 0, .lvl = 22, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Channeler7[] = { +static const struct TrainerMon sParty_Channeler7[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Channeler8[] = { +static const struct TrainerMon sParty_Channeler8[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GASTLY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerAmanda[] = { +static const struct TrainerMon sParty_ChannelerAmanda[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_GASTLY, }, { - .iv = 0, .lvl = 34, .species = SPECIES_HAUNTER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerStacy[] = { +static const struct TrainerMon sParty_ChannelerStacy[] = { { - .iv = 0, .lvl = 38, .species = SPECIES_HAUNTER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_ChannelerTasha[] = { +static const struct TrainerMon sParty_ChannelerTasha[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_GASTLY, }, { - .iv = 0, .lvl = 33, .species = SPECIES_GASTLY, }, { - .iv = 0, .lvl = 33, .species = SPECIES_HAUNTER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerJeremy[] = { +static const struct TrainerMon sParty_HikerJeremy[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 20, .species = SPECIES_ONIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerAlma[] = { +static const struct TrainerMon sParty_PicnickerAlma[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 28, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 28, .species = SPECIES_HORSEA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerSusie[] = { +static const struct TrainerMon sParty_PicnickerSusie[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 24, .species = SPECIES_MEOWTH, }, { - .iv = 0, .lvl = 24, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 24, .species = SPECIES_PIKACHU, }, { - .iv = 0, .lvl = 24, .species = SPECIES_MEOWTH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerValerie[] = { +static const struct TrainerMon sParty_PicnickerValerie[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 30, .species = SPECIES_POLIWAG, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerGwen[] = { +static const struct TrainerMon sParty_PicnickerGwen[] = { { - .iv = 0, .lvl = 27, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 27, .species = SPECIES_MEOWTH, }, { - .iv = 0, .lvl = 27, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 27, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerVirgil[] = { +static const struct TrainerMon sParty_BikerVirgil[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_KOFFING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 28, .species = SPECIES_WEEZING, .moves = {MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperFlint[] = { +static const struct TrainerMon sParty_CamperFlint[] = { { - .iv = 0, .lvl = 14, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 14, .species = SPECIES_EKANS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerMissy[] = { +static const struct TrainerMon sParty_PicnickerMissy[] = { { - .iv = 0, .lvl = 31, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 31, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerIrene[] = { +static const struct TrainerMon sParty_PicnickerIrene[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 30, .species = SPECIES_HORSEA, }, { - .iv = 0, .lvl = 30, .species = SPECIES_SEEL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerDana[] = { +static const struct TrainerMon sParty_PicnickerDana[] = { { - .iv = 0, .lvl = 20, .species = SPECIES_MEOWTH, }, { - .iv = 0, .lvl = 20, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 20, .species = SPECIES_PIDGEY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerAriana[] = { +static const struct TrainerMon sParty_PicnickerAriana[] = { { - .iv = 0, .lvl = 19, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 19, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 19, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 19, .species = SPECIES_BELLSPROUT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerLeah[] = { +static const struct TrainerMon sParty_PicnickerLeah[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_BELLSPROUT, }, { - .iv = 0, .lvl = 22, .species = SPECIES_CLEFAIRY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperJustin[] = { +static const struct TrainerMon sParty_CamperJustin[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_NIDORAN_M, }, { - .iv = 0, .lvl = 29, .species = SPECIES_NIDORINO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerYazmin[] = { +static const struct TrainerMon sParty_PicnickerYazmin[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_BELLSPROUT, }, { - .iv = 0, .lvl = 29, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 29, .species = SPECIES_TANGELA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerKindra[] = { +static const struct TrainerMon sParty_PicnickerKindra[] = { { - .iv = 0, .lvl = 28, .species = SPECIES_GLOOM, }, { - .iv = 0, .lvl = 28, .species = SPECIES_ODDISH, }, { - .iv = 0, .lvl = 28, .species = SPECIES_ODDISH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerBecky[] = { +static const struct TrainerMon sParty_PicnickerBecky[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_PIKACHU, }, { - .iv = 0, .lvl = 29, .species = SPECIES_RAICHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerCelia[] = { +static const struct TrainerMon sParty_PicnickerCelia[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_CLEFAIRY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GentlemanBrooks[] = { +static const struct TrainerMon sParty_GentlemanBrooks[] = { { - .iv = 0, .lvl = 23, .species = SPECIES_PIKACHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GentlemanLamar[] = { +static const struct TrainerMon sParty_GentlemanLamar[] = { { - .iv = 0, .lvl = 17, .species = SPECIES_GROWLITHE, }, { - .iv = 0, .lvl = 17, .species = SPECIES_PONYTA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TwinsEliAnne[] = { +static const struct TrainerMon sParty_TwinsEliAnne[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_CLEFAIRY, }, { - .iv = 0, .lvl = 22, .species = SPECIES_JIGGLYPUFF, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CoolCoupleRayTyra[] = { +static const struct TrainerMon sParty_CoolCoupleRayTyra[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 45, .species = SPECIES_NIDOQUEEN, .moves = {MOVE_SUPERPOWER, MOVE_BODY_SLAM, MOVE_DOUBLE_KICK, MOVE_POISON_STING}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 45, .species = SPECIES_NIDOKING, .moves = {MOVE_MEGAHORN, MOVE_THRASH, MOVE_DOUBLE_KICK, MOVE_POISON_STING}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungCoupleGiaJes[] = { +static const struct TrainerMon sParty_YoungCoupleGiaJes[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_NIDORAN_M, }, { - .iv = 0, .lvl = 24, .species = SPECIES_NIDORAN_F, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TwinsKiriJan[] = { +static const struct TrainerMon sParty_TwinsKiriJan[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_CHARMANDER, }, { - .iv = 0, .lvl = 29, .species = SPECIES_SQUIRTLE, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushKinRonMya[] = { +static const struct TrainerMon sParty_CrushKinRonMya[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 29, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 29, .species = SPECIES_HITMONLEE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungCoupleLeaJed[] = { +static const struct TrainerMon sParty_YoungCoupleLeaJed[] = { { - .iv = 0, .lvl = 29, .species = SPECIES_RAPIDASH, }, { - .iv = 0, .lvl = 29, .species = SPECIES_NINETALES, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SisAndBroLiaLuc[] = { +static const struct TrainerMon sParty_SisAndBroLiaLuc[] = { { - .iv = 0, .lvl = 30, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 30, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SisAndBroLilIan[] = { +static const struct TrainerMon sParty_SisAndBroLilIan[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_SEADRA, }, { - .iv = 0, .lvl = 33, .species = SPECIES_STARMIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcher3[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcher4[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcher5[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcher6[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcher7[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcher8[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BugCatcher3[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BugCatcher4[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BugCatcher5[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BugCatcher6[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BugCatcher7[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_BugCatcher8[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterBen3[] = { +static const struct TrainerMon sParty_YoungsterBen3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_RATICATE, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_EKANS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterBen4[] = { +static const struct TrainerMon sParty_YoungsterBen4[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 48, .species = SPECIES_RATICATE, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 48, .species = SPECIES_ARBOK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterChad2[] = { +static const struct TrainerMon sParty_YoungsterChad2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 20, .species = SPECIES_EKANS, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 20, .species = SPECIES_SANDSHREW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassReli2[] = { +static const struct TrainerMon sParty_LassReli2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 20, .species = SPECIES_PIDGEY, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 20, .species = SPECIES_NIDORAN_F, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassReli3[] = { +static const struct TrainerMon sParty_LassReli3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_PIDGEOTTO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_NIDORINA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterTimmy2[] = { +static const struct TrainerMon sParty_YoungsterTimmy2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 19, .species = SPECIES_RATICATE, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 19, .species = SPECIES_EKANS, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 19, .species = SPECIES_ZUBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterTimmy3[] = { +static const struct TrainerMon sParty_YoungsterTimmy3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_RATICATE, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_EKANS, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_GOLBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterTimmy4[] = { +static const struct TrainerMon sParty_YoungsterTimmy4[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_RATICATE, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_ARBOK, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_GOLBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterChad3[] = { +static const struct TrainerMon sParty_YoungsterChad3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_ARBOK, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_SANDSHREW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassJanice2[] = { +static const struct TrainerMon sParty_LassJanice2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 20, .species = SPECIES_PIDGEOTTO, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 20, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassJanice3[] = { +static const struct TrainerMon sParty_LassJanice3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_PIDGEOTTO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterChad4[] = { +static const struct TrainerMon sParty_YoungsterChad4[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_ARBOK, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_SANDSLASH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerFranklin2[] = { +static const struct TrainerMon sParty_HikerFranklin2[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 25, .species = SPECIES_MACHOKE, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 25, .species = SPECIES_GRAVELER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PkmnProfProfOak[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_PlayerBrendan[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_PlayerMay[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_PlayerRed[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_PlayerLeaf[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_PkmnProfProfOak[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_PlayerBrendan[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_PlayerMay[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_PlayerRed[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_PlayerLeaf[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt42[] = { +static const struct TrainerMon sParty_TeamRocketGrunt42[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_HOUNDOUR, }, { - .iv = 0, .lvl = 49, .species = SPECIES_HOUNDOUR, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PsychicJaclyn[] = { +static const struct TrainerMon sParty_PsychicJaclyn[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_NATU, .moves = {MOVE_NIGHT_SHADE, MOVE_CONFUSE_RAY, MOVE_FUTURE_SIGHT, MOVE_WISH}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_SLOWBRO, .moves = {MOVE_PSYCHIC, MOVE_HEADBUTT, MOVE_AMNESIA, MOVE_YAWN}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 49, .species = SPECIES_KADABRA, .moves = {MOVE_PSYCHIC, MOVE_FUTURE_SIGHT, MOVE_RECOVER, MOVE_REFLECT}, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushGirlSharon[] = { +static const struct TrainerMon sParty_CrushGirlSharon[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 37, .species = SPECIES_MANKEY, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 37, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TuberAmira[] = { +static const struct TrainerMon sParty_TuberAmira[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_POLIWAG, }, { - .iv = 0, .lvl = 35, .species = SPECIES_POLIWHIRL, }, { - .iv = 0, .lvl = 34, .species = SPECIES_POLIWAG, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PkmnBreederAlize[] = { +static const struct TrainerMon sParty_PkmnBreederAlize[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 48, .species = SPECIES_PIKACHU, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 48, .species = SPECIES_CLEFAIRY, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 48, .species = SPECIES_MARILL, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PkmnRangerNicolas[] = { +static const struct TrainerMon sParty_PkmnRangerNicolas[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 51, .species = SPECIES_WEEPINBELL, .moves = {MOVE_RAZOR_LEAF, MOVE_ACID, MOVE_SWEET_SCENT, MOVE_WRAP}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 51, .species = SPECIES_VICTREEBEL, .moves = {MOVE_RAZOR_LEAF, MOVE_ACID, MOVE_SLEEP_POWDER, MOVE_STUN_SPORE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PkmnRangerMadeline[] = { +static const struct TrainerMon sParty_PkmnRangerMadeline[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 51, .species = SPECIES_GLOOM, .moves = {MOVE_PETAL_DANCE, MOVE_ACID, MOVE_SWEET_SCENT, MOVE_POISON_POWDER}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 51, .species = SPECIES_VILEPLUME, .moves = {MOVE_PETAL_DANCE, MOVE_MOONLIGHT, MOVE_ACID, MOVE_STUN_SPORE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_AromaLadyNikki[] = { +static const struct TrainerMon sParty_AromaLadyNikki[] = { { - .iv = 0, .lvl = 37, .species = SPECIES_BELLSPROUT, }, { - .iv = 0, .lvl = 37, .species = SPECIES_WEEPINBELL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RuinManiacStanly[] = { +static const struct TrainerMon sParty_RuinManiacStanly[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_GRAVELER, }, { - .iv = 0, .lvl = 48, .species = SPECIES_ONIX, }, { - .iv = 0, .lvl = 48, .species = SPECIES_GRAVELER, }, }; -static const struct TrainerMonItemDefaultMoves sParty_LadyJacki[] = { +static const struct TrainerMon sParty_LadyJacki[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_HOPPIP, .heldItem = ITEM_STARDUST, }, { - .iv = 0, .lvl = 50, .species = SPECIES_SKIPLOOM, .heldItem = ITEM_STARDUST, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PainterDaisy[] = { +static const struct TrainerMon sParty_PainterDaisy[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 50, .species = SPECIES_SMEARGLE, .moves = {MOVE_DYNAMIC_PUNCH, MOVE_DIZZY_PUNCH, MOVE_FOCUS_PUNCH, MOVE_MEGA_PUNCH}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerGoon[] = { +static const struct TrainerMon sParty_BikerGoon[] = { { - .iv = 0, .lvl = 37, .species = SPECIES_KOFFING, .moves = {MOVE_HAZE, MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_TACKLE}, }, { - .iv = 0, .lvl = 37, .species = SPECIES_GRIMER, .moves = {MOVE_ACID_ARMOR, MOVE_SCREECH, MOVE_MINIMIZE, MOVE_SLUDGE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerGoon2[] = { +static const struct TrainerMon sParty_BikerGoon2[] = { { - .iv = 0, .lvl = 38, .species = SPECIES_KOFFING, .moves = {MOVE_HAZE, MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_TACKLE}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BikerGoon3[] = { +static const struct TrainerMon sParty_BikerGoon3[] = { { - .iv = 0, .lvl = 38, .species = SPECIES_GRIMER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_Biker2[] = {DUMMY_TRAINER_MON}; +static const struct TrainerMon sParty_Biker2[] = {DUMMY_TRAINER_MON}; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherAnthony[] = { +static const struct TrainerMon sParty_BugCatcherAnthony[] = { { - .iv = 0, .lvl = 7, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 8, .species = SPECIES_CATERPIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherCharlie[] = { +static const struct TrainerMon sParty_BugCatcherCharlie[] = { { - .iv = 0, .lvl = 7, .species = SPECIES_METAPOD, }, { - .iv = 0, .lvl = 7, .species = SPECIES_CATERPIE, }, { - .iv = 0, .lvl = 7, .species = SPECIES_METAPOD, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TwinsEliAnne2[] = { +static const struct TrainerMon sParty_TwinsEliAnne2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_CLEFAIRY, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_JIGGLYPUFF, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterJohnson[] = { +static const struct TrainerMon sParty_YoungsterJohnson[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_EKANS, }, { - .iv = 0, .lvl = 33, .species = SPECIES_EKANS, }, { - .iv = 0, .lvl = 34, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_BikerRicardo[] = { +static const struct TrainerMon sParty_BikerRicardo[] = { { - .iv = 0, .lvl = 22, .species = SPECIES_KOFFING, .moves = {MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE, MOVE_POISON_GAS}, }, { - .iv = 0, .lvl = 22, .species = SPECIES_KOFFING, .moves = {MOVE_SLUDGE, MOVE_SMOG, MOVE_TACKLE, MOVE_POISON_GAS}, }, { - .iv = 0, .lvl = 23, .species = SPECIES_GRIMER, .moves = {MOVE_MINIMIZE, MOVE_SLUDGE, MOVE_DISABLE, MOVE_POUND}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BikerJaren[] = { +static const struct TrainerMon sParty_BikerJaren[] = { { - .iv = 0, .lvl = 24, .species = SPECIES_GRIMER, }, { - .iv = 0, .lvl = 24, .species = SPECIES_GRIMER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt43[] = { +static const struct TrainerMon sParty_TeamRocketGrunt43[] = { { - .iv = 0, .lvl = 37, .species = SPECIES_CUBONE, }, { - .iv = 0, .lvl = 37, .species = SPECIES_MAROWAK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt44[] = { +static const struct TrainerMon sParty_TeamRocketGrunt44[] = { { - .iv = 0, .lvl = 35, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 35, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 35, .species = SPECIES_SANDSHREW, }, { - .iv = 0, .lvl = 35, .species = SPECIES_SANDSLASH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt45[] = { +static const struct TrainerMon sParty_TeamRocketGrunt45[] = { { - .iv = 0, .lvl = 38, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 38, .species = SPECIES_ZUBAT, }, { - .iv = 0, .lvl = 38, .species = SPECIES_GOLBAT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt46[] = { +static const struct TrainerMon sParty_TeamRocketGrunt46[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_MUK, }, { - .iv = 0, .lvl = 48, .species = SPECIES_GOLBAT, }, { - .iv = 0, .lvl = 48, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt47[] = { +static const struct TrainerMon sParty_TeamRocketGrunt47[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 48, .species = SPECIES_MACHOP, }, { - .iv = 0, .lvl = 48, .species = SPECIES_MACHOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt48[] = { +static const struct TrainerMon sParty_TeamRocketGrunt48[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_HYPNO, }, { - .iv = 0, .lvl = 49, .species = SPECIES_HYPNO, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_TeamRocketAdmin[] = { +static const struct TrainerMon sParty_TeamRocketAdmin[] = { { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 52, .species = SPECIES_MUK, .moves = {MOVE_SLUDGE_BOMB, MOVE_SCREECH, MOVE_MINIMIZE, MOVE_ROCK_TOMB}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 53, .species = SPECIES_ARBOK, .moves = {MOVE_SLUDGE_BOMB, MOVE_BITE, MOVE_EARTHQUAKE, MOVE_IRON_TAIL}, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 54, .species = SPECIES_VILEPLUME, .moves = {MOVE_SLUDGE_BOMB, MOVE_GIGA_DRAIN, MOVE_SLEEP_POWDER, MOVE_STUN_SPORE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_TeamRocketAdmin2[] = { +static const struct TrainerMon sParty_TeamRocketAdmin2[] = { { - .iv = 200, + .iv = TRAINER_PARTY_IVS(24, 24, 24, 24, 24, 24), .lvl = 53, .species = SPECIES_GOLBAT, .moves = {MOVE_CONFUSE_RAY, MOVE_SLUDGE_BOMB, MOVE_AIR_CUTTER, MOVE_SHADOW_BALL}, }, { - .iv = 200, + .iv = TRAINER_PARTY_IVS(24, 24, 24, 24, 24, 24), .lvl = 54, .species = SPECIES_WEEZING, .moves = {MOVE_SLUDGE_BOMB, MOVE_THUNDERBOLT, MOVE_EXPLOSION, MOVE_SHADOW_BALL}, }, { - .iv = 200, + .iv = TRAINER_PARTY_IVS(24, 24, 24, 24, 24, 24), .lvl = 55, .species = SPECIES_HOUNDOOM, .moves = {MOVE_FLAMETHROWER, MOVE_CRUNCH, MOVE_IRON_TAIL, MOVE_SHADOW_BALL}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_ScientistGideon[] = { +static const struct TrainerMon sParty_ScientistGideon[] = { { - .iv = 0, .lvl = 46, .species = SPECIES_VOLTORB, .moves = {MOVE_SWIFT, MOVE_SCREECH, MOVE_SPARK, MOVE_SONIC_BOOM}, }, { - .iv = 0, .lvl = 46, .species = SPECIES_ELECTRODE, .moves = {MOVE_SPARK, MOVE_SONIC_BOOM, MOVE_SCREECH, MOVE_CHARGE}, }, { - .iv = 0, .lvl = 46, .species = SPECIES_MAGNEMITE, .moves = {MOVE_SCREECH, MOVE_SWIFT, MOVE_SPARK, MOVE_THUNDER_WAVE}, }, { - .iv = 0, .lvl = 46, .species = SPECIES_MAGNETON, .moves = {MOVE_TRI_ATTACK, MOVE_SPARK, MOVE_THUNDER_WAVE, MOVE_SONIC_BOOM}, }, { - .iv = 0, .lvl = 46, .species = SPECIES_PORYGON, .moves = {MOVE_TRI_ATTACK, MOVE_CONVERSION, MOVE_RECOVER, MOVE_PSYBEAM}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleAmara[] = { +static const struct TrainerMon sParty_SwimmerFemaleAmara[] = { { - .iv = 0, .lvl = 36, .species = SPECIES_SEEL, }, { - .iv = 0, .lvl = 36, .species = SPECIES_SEEL, }, { - .iv = 0, .lvl = 36, .species = SPECIES_DEWGONG, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleMaria[] = { +static const struct TrainerMon sParty_SwimmerFemaleMaria[] = { { - .iv = 0, .lvl = 37, .species = SPECIES_SEADRA, }, { - .iv = 0, .lvl = 37, .species = SPECIES_SEADRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleAbigail[] = { +static const struct TrainerMon sParty_SwimmerFemaleAbigail[] = { { - .iv = 0, .lvl = 35, .species = SPECIES_PSYDUCK, }, { - .iv = 0, .lvl = 36, .species = SPECIES_PSYDUCK, }, { - .iv = 0, .lvl = 37, .species = SPECIES_GOLDUCK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleFinn[] = { +static const struct TrainerMon sParty_SwimmerMaleFinn[] = { { - .iv = 0, .lvl = 38, .species = SPECIES_STARMIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleGarrett[] = { +static const struct TrainerMon sParty_SwimmerMaleGarrett[] = { { - .iv = 0, .lvl = 35, .species = SPECIES_SHELLDER, }, { - .iv = 0, .lvl = 35, .species = SPECIES_CLOYSTER, }, { - .iv = 0, .lvl = 38, .species = SPECIES_WARTORTLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanTommy[] = { +static const struct TrainerMon sParty_FishermanTommy[] = { { - .iv = 0, .lvl = 33, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 33, .species = SPECIES_GOLDEEN, }, { - .iv = 0, .lvl = 35, .species = SPECIES_SEAKING, }, { - .iv = 0, .lvl = 35, .species = SPECIES_SEAKING, }, { - .iv = 0, .lvl = 35, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushGirlTanya[] = { +static const struct TrainerMon sParty_CrushGirlTanya[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 38, .species = SPECIES_HITMONLEE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 38, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltShea[] = { +static const struct TrainerMon sParty_BlackBeltShea[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_MACHOP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltHugh[] = { +static const struct TrainerMon sParty_BlackBeltHugh[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_MACHOP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperBryce[] = { +static const struct TrainerMon sParty_CamperBryce[] = { { - .iv = 0, .lvl = 36, .species = SPECIES_NIDORINO, }, { - .iv = 0, .lvl = 36, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 36, .species = SPECIES_SANDSLASH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerClaire[] = { +static const struct TrainerMon sParty_PicnickerClaire[] = { { - .iv = 0, .lvl = 35, .species = SPECIES_MEOWTH, }, { - .iv = 0, .lvl = 35, .species = SPECIES_MEOWTH, }, { - .iv = 0, .lvl = 35, .species = SPECIES_PIKACHU, }, { - .iv = 0, .lvl = 35, .species = SPECIES_CLEFAIRY, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushKinMikKia[] = { +static const struct TrainerMon sParty_CrushKinMikKia[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 39, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 39, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_AromaLadyViolet[] = { +static const struct TrainerMon sParty_AromaLadyViolet[] = { { - .iv = 0, .lvl = 36, .species = SPECIES_BULBASAUR, }, { - .iv = 0, .lvl = 36, .species = SPECIES_IVYSAUR, }, { - .iv = 0, .lvl = 36, .species = SPECIES_IVYSAUR, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TuberAlexis[] = { +static const struct TrainerMon sParty_TuberAlexis[] = { { - .iv = 0, .lvl = 34, .species = SPECIES_STARYU, }, { - .iv = 0, .lvl = 34, .species = SPECIES_STARYU, }, { - .iv = 0, .lvl = 34, .species = SPECIES_KRABBY, }, { - .iv = 0, .lvl = 34, .species = SPECIES_KRABBY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TwinsJoyMeg[] = { +static const struct TrainerMon sParty_TwinsJoyMeg[] = { { - .iv = 0, .lvl = 37, .species = SPECIES_CLEFAIRY, }, { - .iv = 0, .lvl = 37, .species = SPECIES_CLEFAIRY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleTisha[] = { +static const struct TrainerMon sParty_SwimmerFemaleTisha[] = { { - .iv = 0, .lvl = 38, .species = SPECIES_KINGLER, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PainterCelina[] = { +static const struct TrainerMon sParty_PainterCelina[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 50, .species = SPECIES_SMEARGLE, .moves = {MOVE_FLY, MOVE_DIG, MOVE_DIVE, MOVE_BOUNCE}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PainterRayna[] = { +static const struct TrainerMon sParty_PainterRayna[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 50, .species = SPECIES_SMEARGLE, .moves = {MOVE_CROSS_CHOP, MOVE_MEGAHORN, MOVE_DOUBLE_EDGE, MOVE_SELF_DESTRUCT}, }, }; -static const struct TrainerMonItemDefaultMoves sParty_LadyGillian[] = { +static const struct TrainerMon sParty_LadyGillian[] = { { - .iv = 0, .lvl = 47, .species = SPECIES_MAREEP, .heldItem = ITEM_STARDUST, }, { - .iv = 0, .lvl = 48, .species = SPECIES_MAREEP, .heldItem = ITEM_STARDUST, }, { - .iv = 0, .lvl = 49, .species = SPECIES_FLAAFFY, .heldItem = ITEM_NUGGET, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterDestin[] = { +static const struct TrainerMon sParty_YoungsterDestin[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_RATICATE, }, { - .iv = 0, .lvl = 48, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleToby[] = { +static const struct TrainerMon sParty_SwimmerMaleToby[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_POLIWHIRL, }, { - .iv = 0, .lvl = 48, .species = SPECIES_TENTACOOL, }, { - .iv = 0, .lvl = 48, .species = SPECIES_TENTACRUEL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt49[] = { +static const struct TrainerMon sParty_TeamRocketGrunt49[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_RATTATA, }, { - .iv = 0, .lvl = 48, .species = SPECIES_GRIMER, }, { - .iv = 0, .lvl = 48, .species = SPECIES_MUK, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_TeamRocketGrunt50[] = { +static const struct TrainerMon sParty_TeamRocketGrunt50[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_KOFFING, .moves = {MOVE_MEMENTO, MOVE_HAZE, MOVE_SMOKESCREEN, MOVE_SLUDGE}, }, { - .iv = 0, .lvl = 49, .species = SPECIES_WEEZING, .moves = {MOVE_HAZE, MOVE_SMOKESCREEN, MOVE_SLUDGE, MOVE_SELF_DESTRUCT}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TeamRocketGrunt51[] = { +static const struct TrainerMon sParty_TeamRocketGrunt51[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 48, .species = SPECIES_EKANS, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 48, .species = SPECIES_GLOOM, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 48, .species = SPECIES_GLOOM, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperMilo[] = { +static const struct TrainerMon sParty_BirdKeeperMilo[] = { { - .iv = 0, .lvl = 47, .species = SPECIES_PIDGEY, }, { - .iv = 0, .lvl = 49, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperChaz[] = { +static const struct TrainerMon sParty_BirdKeeperChaz[] = { { - .iv = 0, .lvl = 47, .species = SPECIES_SPEAROW, }, { - .iv = 0, .lvl = 49, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperHarold[] = { +static const struct TrainerMon sParty_BirdKeeperHarold[] = { { - .iv = 0, .lvl = 47, .species = SPECIES_HOOTHOOT, }, { - .iv = 0, .lvl = 49, .species = SPECIES_NOCTOWL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanTylor[] = { +static const struct TrainerMon sParty_FishermanTylor[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_QWILFISH, }, { - .iv = 0, .lvl = 49, .species = SPECIES_QWILFISH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleMymo[] = { +static const struct TrainerMon sParty_SwimmerMaleMymo[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_KINGLER, }, { - .iv = 0, .lvl = 49, .species = SPECIES_WARTORTLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleNicole[] = { +static const struct TrainerMon sParty_SwimmerFemaleNicole[] = { { - .iv = 0, .lvl = 50, .species = SPECIES_MARILL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SisAndBroAvaGeb[] = { +static const struct TrainerMon sParty_SisAndBroAvaGeb[] = { { - .iv = 0, .lvl = 50, .species = SPECIES_POLIWHIRL, }, { - .iv = 0, .lvl = 50, .species = SPECIES_STARMIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_AromaLadyRose[] = { +static const struct TrainerMon sParty_AromaLadyRose[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_SUNKERN, }, { - .iv = 0, .lvl = 49, .species = SPECIES_SUNFLORA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleSamir[] = { +static const struct TrainerMon sParty_SwimmerMaleSamir[] = { { - .iv = 0, .lvl = 50, .species = SPECIES_GYARADOS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleDenise[] = { +static const struct TrainerMon sParty_SwimmerFemaleDenise[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_CHINCHOU, }, { - .iv = 0, .lvl = 49, .species = SPECIES_LANTURN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TwinsMiuMia[] = { +static const struct TrainerMon sParty_TwinsMiuMia[] = { { - .iv = 0, .lvl = 50, .species = SPECIES_PIKACHU, }, { - .iv = 0, .lvl = 50, .species = SPECIES_PIKACHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerEarl[] = { +static const struct TrainerMon sParty_HikerEarl[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_ONIX, }, { - .iv = 0, .lvl = 49, .species = SPECIES_MACHOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RuinManiacFoster[] = { +static const struct TrainerMon sParty_RuinManiacFoster[] = { { - .iv = 0, .lvl = 50, .species = SPECIES_GOLEM, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RuinManiacLarry[] = { +static const struct TrainerMon sParty_RuinManiacLarry[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_MACHOKE, }, { - .iv = 0, .lvl = 49, .species = SPECIES_MACHOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerDaryl[] = { +static const struct TrainerMon sParty_HikerDaryl[] = { { - .iv = 0, .lvl = 50, .species = SPECIES_SUDOWOODO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacHector[] = { +static const struct TrainerMon sParty_PokemaniacHector[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 49, .species = SPECIES_RHYHORN, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 49, .species = SPECIES_KANGASKHAN, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PsychicDario[] = { +static const struct TrainerMon sParty_PsychicDario[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 52, .species = SPECIES_GIRAFARIG, .moves = {MOVE_CRUNCH, MOVE_PSYBEAM, MOVE_ODOR_SLEUTH, MOVE_AGILITY}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PsychicRodette[] = { +static const struct TrainerMon sParty_PsychicRodette[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_NATU, .moves = {MOVE_NIGHT_SHADE, MOVE_CONFUSE_RAY, MOVE_WISH, MOVE_FUTURE_SIGHT}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_DROWZEE, .moves = {MOVE_PSYCHIC, MOVE_DISABLE, MOVE_PSYCH_UP, MOVE_FUTURE_SIGHT}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 50, .species = SPECIES_HYPNO, .moves = {MOVE_PSYCHIC, MOVE_HYPNOSIS, MOVE_PSYCH_UP, MOVE_FUTURE_SIGHT}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_AromaLadyMiah[] = { +static const struct TrainerMon sParty_AromaLadyMiah[] = { { - .iv = 0, .lvl = 50, .species = SPECIES_BELLOSSOM, }, { - .iv = 0, .lvl = 50, .species = SPECIES_BELLOSSOM, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungCoupleEveJon[] = { +static const struct TrainerMon sParty_YoungCoupleEveJon[] = { { - .iv = 0, .lvl = 50, .species = SPECIES_GOLDUCK, }, { - .iv = 0, .lvl = 50, .species = SPECIES_PSYDUCK, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_JugglerMason[] = { +static const struct TrainerMon sParty_JugglerMason[] = { { - .iv = 0, .lvl = 47, .species = SPECIES_VOLTORB, .moves = {MOVE_SWIFT, MOVE_LIGHT_SCREEN, MOVE_SPARK, MOVE_SONIC_BOOM}, }, { - .iv = 0, .lvl = 47, .species = SPECIES_PINECO, .moves = {MOVE_SPIKES, MOVE_BIDE, MOVE_RAPID_SPIN, MOVE_TAKE_DOWN}, }, { - .iv = 0, .lvl = 47, .species = SPECIES_VOLTORB, .moves = {MOVE_SWIFT, MOVE_LIGHT_SCREEN, MOVE_SPARK, MOVE_SONIC_BOOM}, }, { - .iv = 0, .lvl = 47, .species = SPECIES_PINECO, .moves = {MOVE_SPIKES, MOVE_BIDE, MOVE_RAPID_SPIN, MOVE_EXPLOSION}, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushGirlCyndy[] = { +static const struct TrainerMon sParty_CrushGirlCyndy[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 48, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 48, .species = SPECIES_HITMONTOP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 48, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushGirlJocelyn[] = { +static const struct TrainerMon sParty_CrushGirlJocelyn[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 38, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 38, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TamerEvan[] = { +static const struct TrainerMon sParty_TamerEvan[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 48, .species = SPECIES_SANDSLASH, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 48, .species = SPECIES_LICKITUNG, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 49, .species = SPECIES_URSARING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacMark2[] = { +static const struct TrainerMon sParty_PokemaniacMark2[] = { { - .iv = 90, + .iv = TRAINER_PARTY_IVS(10, 10, 10, 10, 10, 10), .lvl = 33, .species = SPECIES_RHYHORN, }, { - .iv = 90, + .iv = TRAINER_PARTY_IVS(10, 10, 10, 10, 10, 10), .lvl = 33, .species = SPECIES_LICKITUNG, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PkmnRangerLogan[] = { +static const struct TrainerMon sParty_PkmnRangerLogan[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 37, .species = SPECIES_EXEGGCUTE, .moves = {MOVE_SLEEP_POWDER, MOVE_POISON_POWDER, MOVE_STUN_SPORE, MOVE_CONFUSION}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 40, .species = SPECIES_EXEGGUTOR, .moves = {MOVE_EGG_BOMB, MOVE_STOMP, MOVE_CONFUSION, MOVE_HYPNOSIS}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PkmnRangerJackson[] = { +static const struct TrainerMon sParty_PkmnRangerJackson[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 49, .species = SPECIES_TANGELA, .moves = {MOVE_SLAM, MOVE_MEGA_DRAIN, MOVE_BIND, MOVE_INGRAIN}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 49, .species = SPECIES_EXEGGCUTE, .moves = {MOVE_CONFUSION, MOVE_POISON_POWDER, MOVE_BARRAGE, MOVE_REFLECT}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 49, .species = SPECIES_EXEGGUTOR, .moves = {MOVE_CONFUSION, MOVE_EGG_BOMB, MOVE_SLEEP_POWDER, MOVE_STOMP}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PkmnRangerBeth[] = { +static const struct TrainerMon sParty_PkmnRangerBeth[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_BELLSPROUT, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_GLOOM, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 38, .species = SPECIES_GLOOM, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PkmnRangerKatelyn[] = { +static const struct TrainerMon sParty_PkmnRangerKatelyn[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 52, .species = SPECIES_CHANSEY, .moves = {MOVE_EGG_BOMB, MOVE_DEFENSE_CURL, MOVE_MINIMIZE, MOVE_SOFT_BOILED}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerLeroy[] = { +static const struct TrainerMon sParty_CooltrainerLeroy[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 47, .species = SPECIES_RHYDON, .moves = {MOVE_TAKE_DOWN, MOVE_HORN_DRILL, MOVE_ROCK_BLAST, MOVE_SCARY_FACE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_SLOWBRO, .moves = {MOVE_PSYCHIC, MOVE_HEADBUTT, MOVE_AMNESIA, MOVE_DISABLE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 47, .species = SPECIES_KANGASKHAN, .moves = {MOVE_DIZZY_PUNCH, MOVE_BITE, MOVE_ENDURE, MOVE_REVERSAL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_MACHOKE, .moves = {MOVE_CROSS_CHOP, MOVE_VITAL_THROW, MOVE_REVENGE, MOVE_SEISMIC_TOSS}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 50, .species = SPECIES_URSARING, .moves = {MOVE_SLASH, MOVE_FAINT_ATTACK, MOVE_SNORE, MOVE_REST}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerMichelle[] = { +static const struct TrainerMon sParty_CooltrainerMichelle[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 47, .species = SPECIES_PERSIAN, .moves = {MOVE_SLASH, MOVE_SCREECH, MOVE_FAINT_ATTACK, MOVE_BITE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 47, .species = SPECIES_DEWGONG, .moves = {MOVE_ICE_BEAM, MOVE_TAKE_DOWN, MOVE_ICY_WIND, MOVE_GROWL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_NINETALES, .moves = {MOVE_FLAMETHROWER, MOVE_CONFUSE_RAY, MOVE_WILL_O_WISP, MOVE_GRUDGE}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_RAPIDASH, .moves = {MOVE_BOUNCE, MOVE_AGILITY, MOVE_FIRE_SPIN, MOVE_TAKE_DOWN}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 50, .species = SPECIES_GIRAFARIG, .moves = {MOVE_CRUNCH, MOVE_PSYBEAM, MOVE_STOMP, MOVE_ODOR_SLEUTH}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CoolCoupleLexNya[] = { +static const struct TrainerMon sParty_CoolCoupleLexNya[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 52, .species = SPECIES_MILTANK, .moves = {MOVE_BODY_SLAM, MOVE_MILK_DRINK, MOVE_GROWL, MOVE_DEFENSE_CURL}, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 52, .species = SPECIES_TAUROS, .moves = {MOVE_THRASH, MOVE_HORN_ATTACK, MOVE_PURSUIT, MOVE_SWAGGER}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RuinManiacBrandon[] = { +static const struct TrainerMon sParty_RuinManiacBrandon[] = { { - .iv = 0, .lvl = 50, .species = SPECIES_ONIX, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_RuinManiacBenjamin[] = { +static const struct TrainerMon sParty_RuinManiacBenjamin[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_GEODUDE, .moves = {MOVE_EARTHQUAKE, MOVE_ROCK_BLAST, MOVE_ROLLOUT, MOVE_SELF_DESTRUCT}, }, { - .iv = 0, .lvl = 48, .species = SPECIES_GRAVELER, .moves = {MOVE_EARTHQUAKE, MOVE_ROCK_BLAST, MOVE_ROCK_THROW, MOVE_SELF_DESTRUCT}, }, { - .iv = 0, .lvl = 48, .species = SPECIES_GRAVELER, .moves = {MOVE_EARTHQUAKE, MOVE_ROCK_BLAST, MOVE_ROCK_THROW, MOVE_SELF_DESTRUCT}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PainterEdna[] = { +static const struct TrainerMon sParty_PainterEdna[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 50, .species = SPECIES_SMEARGLE, .moves = {MOVE_FAKE_OUT, MOVE_EXTREME_SPEED, MOVE_PROTECT, MOVE_QUICK_ATTACK}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GentlemanClifford[] = { +static const struct TrainerMon sParty_GentlemanClifford[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_MAROWAK, }, { - .iv = 0, .lvl = 49, .species = SPECIES_GOLDUCK, }, }; -static const struct TrainerMonItemCustomMoves sParty_LadySelphy[] = { +static const struct TrainerMon sParty_LadySelphy[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_PERSIAN, .heldItem = ITEM_NUGGET, .moves = {MOVE_PAY_DAY, MOVE_BITE, MOVE_TAUNT, MOVE_TORMENT}, }, { - .iv = 0, .lvl = 49, .species = SPECIES_PERSIAN, .heldItem = ITEM_NUGGET, @@ -8555,2043 +7640,2015 @@ static const struct TrainerMonItemCustomMoves sParty_LadySelphy[] = { }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RuinManiacLawson[] = { +static const struct TrainerMon sParty_RuinManiacLawson[] = { { - .iv = 0, .lvl = 47, .species = SPECIES_ONIX, }, { - .iv = 0, .lvl = 48, .species = SPECIES_GRAVELER, }, { - .iv = 0, .lvl = 49, .species = SPECIES_MAROWAK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PsychicLaura[] = { +static const struct TrainerMon sParty_PsychicLaura[] = { { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_NATU, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 48, .species = SPECIES_NATU, }, { - .iv = 100, + .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), .lvl = 49, .species = SPECIES_XATU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PkmnBreederBethany[] = { +static const struct TrainerMon sParty_PkmnBreederBethany[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 50, .species = SPECIES_CHANSEY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PkmnBreederAllison[] = { +static const struct TrainerMon sParty_PkmnBreederAllison[] = { { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 48, .species = SPECIES_CLEFAIRY, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 48, .species = SPECIES_CLEFAIRY, }, { - .iv = 30, + .iv = TRAINER_PARTY_IVS(3, 3, 3, 3, 3, 3), .lvl = 48, .species = SPECIES_CLEFABLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherGarret[] = { +static const struct TrainerMon sParty_BugCatcherGarret[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_HERACROSS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherJonah[] = { +static const struct TrainerMon sParty_BugCatcherJonah[] = { { - .iv = 0, .lvl = 45, .species = SPECIES_YANMA, }, { - .iv = 0, .lvl = 45, .species = SPECIES_BEEDRILL, }, { - .iv = 0, .lvl = 46, .species = SPECIES_YANMA, }, { - .iv = 0, .lvl = 47, .species = SPECIES_BEEDRILL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherVance[] = { +static const struct TrainerMon sParty_BugCatcherVance[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_VENONAT, }, { - .iv = 0, .lvl = 48, .species = SPECIES_VENOMOTH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterNash[] = { +static const struct TrainerMon sParty_YoungsterNash[] = { { - .iv = 0, .lvl = 47, .species = SPECIES_WEEPINBELL, }, { - .iv = 0, .lvl = 47, .species = SPECIES_WEEPINBELL, }, { - .iv = 0, .lvl = 49, .species = SPECIES_VICTREEBEL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterCordell[] = { +static const struct TrainerMon sParty_YoungsterCordell[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_FARFETCHD, }, { - .iv = 0, .lvl = 48, .species = SPECIES_FARFETCHD, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassDalia[] = { +static const struct TrainerMon sParty_LassDalia[] = { { - .iv = 0, .lvl = 46, .species = SPECIES_HOPPIP, }, { - .iv = 0, .lvl = 47, .species = SPECIES_HOPPIP, }, { - .iv = 0, .lvl = 47, .species = SPECIES_SKIPLOOM, }, { - .iv = 0, .lvl = 48, .species = SPECIES_SKIPLOOM, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassJoana[] = { +static const struct TrainerMon sParty_LassJoana[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_SNUBBULL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperRiley[] = { +static const struct TrainerMon sParty_CamperRiley[] = { { - .iv = 0, .lvl = 49, .species = SPECIES_PINSIR, }, { - .iv = 0, .lvl = 50, .species = SPECIES_HERACROSS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerMarcy[] = { +static const struct TrainerMon sParty_PicnickerMarcy[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_PARAS, }, { - .iv = 0, .lvl = 48, .species = SPECIES_PARAS, }, { - .iv = 0, .lvl = 49, .species = SPECIES_PARASECT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RuinManiacLayton[] = { +static const struct TrainerMon sParty_RuinManiacLayton[] = { { - .iv = 0, .lvl = 48, .species = SPECIES_SANDSLASH, }, { - .iv = 0, .lvl = 48, .species = SPECIES_ONIX, }, { - .iv = 0, .lvl = 48, .species = SPECIES_SANDSLASH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerKelsey2[] = { +static const struct TrainerMon sParty_PicnickerKelsey2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 21, .species = SPECIES_NIDORAN_M, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 21, .species = SPECIES_NIDORAN_F, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerKelsey3[] = { +static const struct TrainerMon sParty_PicnickerKelsey3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_NIDORINO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_NIDORINA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerKelsey4[] = { +static const struct TrainerMon sParty_PicnickerKelsey4[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_NIDORINO, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_NIDORINA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperRicky2[] = { +static const struct TrainerMon sParty_CamperRicky2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 22, .species = SPECIES_SQUIRTLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperRicky3[] = { +static const struct TrainerMon sParty_CamperRicky3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_WARTORTLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperRicky4[] = { +static const struct TrainerMon sParty_CamperRicky4[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_WARTORTLE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperJeff2[] = { +static const struct TrainerMon sParty_CamperJeff2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 21, .species = SPECIES_SPEAROW, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 21, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperJeff3[] = { +static const struct TrainerMon sParty_CamperJeff3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_FEAROW, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperJeff4[] = { +static const struct TrainerMon sParty_CamperJeff4[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_FEAROW, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerIsabelle2[] = { +static const struct TrainerMon sParty_PicnickerIsabelle2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 21, .species = SPECIES_PIDGEOTTO, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 21, .species = SPECIES_PIDGEOTTO, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 18, .species = SPECIES_PIDGEY, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerIsabelle3[] = { +static const struct TrainerMon sParty_PicnickerIsabelle3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_PIDGEOTTO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_PIDGEOTTO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 26, .species = SPECIES_PIDGEOTTO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerIsabelle4[] = { +static const struct TrainerMon sParty_PicnickerIsabelle4[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_PIDGEOTTO, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_PIDGEOTTO, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 50, .species = SPECIES_PIDGEOT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterYasu2[] = { +static const struct TrainerMon sParty_YoungsterYasu2[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 22, .species = SPECIES_RATTATA, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 22, .species = SPECIES_RATICATE, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 22, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterYasu3[] = { +static const struct TrainerMon sParty_YoungsterYasu3[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_RATICATE, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_RATICATE, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_RATICATE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_EngineerBernie2[] = { +static const struct TrainerMon sParty_EngineerBernie2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_MAGNETON, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_MAGNETON, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_MAGNETON, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GamerDarian2[] = { +static const struct TrainerMon sParty_GamerDarian2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_GROWLITHE, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_VULPIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperChris2[] = { +static const struct TrainerMon sParty_CamperChris2[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 24, .species = SPECIES_GROWLITHE, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 24, .species = SPECIES_CHARMANDER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperChris3[] = { +static const struct TrainerMon sParty_CamperChris3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_GROWLITHE, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 29, .species = SPECIES_CHARMELEON, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CamperChris4[] = { +static const struct TrainerMon sParty_CamperChris4[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_ARCANINE, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_CHARMELEON, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerAlicia2[] = { +static const struct TrainerMon sParty_PicnickerAlicia2[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 25, .species = SPECIES_MEOWTH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerAlicia3[] = { +static const struct TrainerMon sParty_PicnickerAlicia3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_PERSIAN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerAlicia4[] = { +static const struct TrainerMon sParty_PicnickerAlicia4[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_PERSIAN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerJeremy2[] = { +static const struct TrainerMon sParty_HikerJeremy2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_MACHOKE, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_ONIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacMark3[] = { +static const struct TrainerMon sParty_PokemaniacMark3[] = { { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 54, .species = SPECIES_RHYDON, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 54, .species = SPECIES_LICKITUNG, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacHerman2[] = { +static const struct TrainerMon sParty_PokemaniacHerman2[] = { { - .iv = 90, + .iv = TRAINER_PARTY_IVS(10, 10, 10, 10, 10, 10), .lvl = 29, .species = SPECIES_MAROWAK, }, { - .iv = 90, + .iv = TRAINER_PARTY_IVS(10, 10, 10, 10, 10, 10), .lvl = 29, .species = SPECIES_SLOWBRO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacHerman3[] = { +static const struct TrainerMon sParty_PokemaniacHerman3[] = { { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 54, .species = SPECIES_MAROWAK, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 54, .species = SPECIES_SLOWBRO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerTrent2[] = { +static const struct TrainerMon sParty_HikerTrent2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 31, .species = SPECIES_ONIX, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 31, .species = SPECIES_GRAVELER, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassMegan2[] = { +static const struct TrainerMon sParty_LassMegan2[] = { { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 22, .species = SPECIES_PIDGEOTTO, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 22, .species = SPECIES_RATICATE, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 23, .species = SPECIES_NIDORAN_M, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 21, .species = SPECIES_MEOWTH, }, { - .iv = 40, + .iv = TRAINER_PARTY_IVS(4, 4, 4, 4, 4, 4), .lvl = 22, .species = SPECIES_PIKACHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_LassMegan3[] = { +static const struct TrainerMon sParty_LassMegan3[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 46, .species = SPECIES_PIDGEOT, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_RATICATE, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_NIDORINO, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_PERSIAN, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_RAICHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SuperNerdGlenn2[] = { +static const struct TrainerMon sParty_SuperNerdGlenn2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_MUK, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_MUK, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_MUK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_GamerRich2[] = { +static const struct TrainerMon sParty_GamerRich2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_GROWLITHE, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_VULPIX, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BikerJaren2[] = { +static const struct TrainerMon sParty_BikerJaren2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_MUK, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_MUK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanElliot2[] = { +static const struct TrainerMon sParty_FishermanElliot2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_POLIWHIRL, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_CLOYSTER, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_SEAKING, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_SEADRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RockerLuca2[] = { +static const struct TrainerMon sParty_RockerLuca2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 33, .species = SPECIES_ELECTRODE, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 33, .species = SPECIES_ELECTRODE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautySheila2[] = { +static const struct TrainerMon sParty_BeautySheila2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_CLEFAIRY, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_PERSIAN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperRobert2[] = { +static const struct TrainerMon sParty_BirdKeeperRobert2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_PIDGEOTTO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_PIDGEOTTO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_FEAROW, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperRobert3[] = { +static const struct TrainerMon sParty_BirdKeeperRobert3[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_PIDGEOT, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_PIDGEOT, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_FEAROW, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerSusie2[] = { +static const struct TrainerMon sParty_PicnickerSusie2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_PIDGEOTTO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_MEOWTH, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_RATICATE, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_PIKACHU, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_MEOWTH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerSusie3[] = { +static const struct TrainerMon sParty_PicnickerSusie3[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_PIDGEOTTO, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_PERSIAN, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_RATICATE, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_PIKACHU, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_PERSIAN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerSusie4[] = { +static const struct TrainerMon sParty_PicnickerSusie4[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_PIDGEOT, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_PERSIAN, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_RATICATE, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_RAICHU, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_PERSIAN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BikerLukas2[] = { +static const struct TrainerMon sParty_BikerLukas2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_KOFFING, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_KOFFING, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_MUK, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_WEEZING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperBenny2[] = { +static const struct TrainerMon sParty_BirdKeeperBenny2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 32, .species = SPECIES_FEAROW, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 32, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperBenny3[] = { +static const struct TrainerMon sParty_BirdKeeperBenny3[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_FEAROW, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperMarlon2[] = { +static const struct TrainerMon sParty_BirdKeeperMarlon2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_FEAROW, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_DODUO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperMarlon3[] = { +static const struct TrainerMon sParty_BirdKeeperMarlon3[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_FEAROW, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_DODRIO, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BeautyGrace2[] = { +static const struct TrainerMon sParty_BeautyGrace2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_PIDGEOT, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_WIGGLYTUFF, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperChester2[] = { +static const struct TrainerMon sParty_BirdKeeperChester2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_DODRIO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_DODRIO, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_DODUO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperChester3[] = { +static const struct TrainerMon sParty_BirdKeeperChester3[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_DODRIO, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_DODRIO, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_DODRIO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerBecky2[] = { +static const struct TrainerMon sParty_PicnickerBecky2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 32, .species = SPECIES_PIKACHU, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 32, .species = SPECIES_RAICHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerBecky3[] = { +static const struct TrainerMon sParty_PicnickerBecky3[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_PIKACHU, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_RAICHU, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerBecky4[] = { +static const struct TrainerMon sParty_PicnickerBecky4[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_RAICHU, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_RAICHU, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushKinRonMya2[] = { +static const struct TrainerMon sParty_CrushKinRonMya2[] = { { - .iv = 110, + .iv = TRAINER_PARTY_IVS(13, 13, 13, 13, 13, 13), .lvl = 33, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 110, + .iv = TRAINER_PARTY_IVS(13, 13, 13, 13, 13, 13), .lvl = 33, .species = SPECIES_HITMONLEE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushKinRonMya3[] = { +static const struct TrainerMon sParty_CrushKinRonMya3[] = { { - .iv = 130, + .iv = TRAINER_PARTY_IVS(15, 15, 15, 15, 15, 15), .lvl = 51, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 130, + .iv = TRAINER_PARTY_IVS(15, 15, 15, 15, 15, 15), .lvl = 51, .species = SPECIES_HITMONLEE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushKinRonMya4[] = { +static const struct TrainerMon sParty_CrushKinRonMya4[] = { { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 56, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 56, .species = SPECIES_HITMONLEE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BikerRuben2[] = { +static const struct TrainerMon sParty_BikerRuben2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_WEEZING, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_WEEZING, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 48, .species = SPECIES_WEEZING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallCamron2[] = { +static const struct TrainerMon sParty_CueBallCamron2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_PRIMEAPE, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_MACHOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BikerJaxon2[] = { +static const struct TrainerMon sParty_BikerJaxon2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_WEEZING, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_MUK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallIsaiah2[] = { +static const struct TrainerMon sParty_CueBallIsaiah2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_MACHOKE, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_MACHAMP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallCorey2[] = { +static const struct TrainerMon sParty_CueBallCorey2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_PRIMEAPE, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_MACHAMP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperJacob2[] = { +static const struct TrainerMon sParty_BirdKeeperJacob2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_FEAROW, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_SPEAROW, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_FEAROW, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 28, .species = SPECIES_SPEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperJacob3[] = { +static const struct TrainerMon sParty_BirdKeeperJacob3[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_FEAROW, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_FEAROW, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_FEAROW, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleAlice2[] = { +static const struct TrainerMon sParty_SwimmerFemaleAlice2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_SEAKING, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleDarrin2[] = { +static const struct TrainerMon sParty_SwimmerMaleDarrin2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_SEADRA, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_SEADRA, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_SEADRA, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_SEADRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerMissy2[] = { +static const struct TrainerMon sParty_PicnickerMissy2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_SEAKING, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PicnickerMissy3[] = { +static const struct TrainerMon sParty_PicnickerMissy3[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_SEAKING, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_FishermanWade2[] = { +static const struct TrainerMon sParty_FishermanWade2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_MAGIKARP, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_MAGIKARP, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_MAGIKARP, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_MAGIKARP, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_MAGIKARP, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_MAGIKARP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleJack2[] = { +static const struct TrainerMon sParty_SwimmerMaleJack2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 50, .species = SPECIES_STARMIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SisAndBroLilIan2[] = { +static const struct TrainerMon sParty_SisAndBroLilIan2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 50, .species = SPECIES_SEADRA, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 50, .species = SPECIES_STARMIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SisAndBroLilIan3[] = { +static const struct TrainerMon sParty_SisAndBroLilIan3[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_SEADRA, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_STARMIE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleFinn2[] = { +static const struct TrainerMon sParty_SwimmerMaleFinn2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 50, .species = SPECIES_STARMIE, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushGirlSharon2[] = { +static const struct TrainerMon sParty_CrushGirlSharon2[] = { { - .iv = 130, + .iv = TRAINER_PARTY_IVS(15, 15, 15, 15, 15, 15), .lvl = 50, .species = SPECIES_MANKEY, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 130, + .iv = TRAINER_PARTY_IVS(15, 15, 15, 15, 15, 15), .lvl = 50, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushGirlSharon3[] = { +static const struct TrainerMon sParty_CrushGirlSharon3[] = { { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 55, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 55, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushGirlTanya2[] = { +static const struct TrainerMon sParty_CrushGirlTanya2[] = { { - .iv = 130, + .iv = TRAINER_PARTY_IVS(15, 15, 15, 15, 15, 15), .lvl = 50, .species = SPECIES_HITMONLEE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 130, + .iv = TRAINER_PARTY_IVS(15, 15, 15, 15, 15, 15), .lvl = 50, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushGirlTanya3[] = { +static const struct TrainerMon sParty_CrushGirlTanya3[] = { { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 55, .species = SPECIES_HITMONLEE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 55, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltShea2[] = { +static const struct TrainerMon sParty_BlackBeltShea2[] = { { - .iv = 180, + .iv = TRAINER_PARTY_IVS(21, 21, 21, 21, 21, 21), .lvl = 50, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 180, + .iv = TRAINER_PARTY_IVS(21, 21, 21, 21, 21, 21), .lvl = 50, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltShea3[] = { +static const struct TrainerMon sParty_BlackBeltShea3[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_MACHAMP, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltHugh2[] = { +static const struct TrainerMon sParty_BlackBeltHugh2[] = { { - .iv = 180, + .iv = TRAINER_PARTY_IVS(21, 21, 21, 21, 21, 21), .lvl = 50, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 180, + .iv = TRAINER_PARTY_IVS(21, 21, 21, 21, 21, 21), .lvl = 50, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_BlackBeltHugh3[] = { +static const struct TrainerMon sParty_BlackBeltHugh3[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_MACHAMP, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushKinMikKia2[] = { +static const struct TrainerMon sParty_CrushKinMikKia2[] = { { - .iv = 130, + .iv = TRAINER_PARTY_IVS(15, 15, 15, 15, 15, 15), .lvl = 51, .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 130, + .iv = TRAINER_PARTY_IVS(15, 15, 15, 15, 15, 15), .lvl = 51, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushKinMikKia3[] = { +static const struct TrainerMon sParty_CrushKinMikKia3[] = { { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 56, .species = SPECIES_MACHAMP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 56, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TuberAmira2[] = { +static const struct TrainerMon sParty_TuberAmira2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_POLIWHIRL, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_POLIWHIRL, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 47, .species = SPECIES_POLIWHIRL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TwinsJoyMeg2[] = { +static const struct TrainerMon sParty_TwinsJoyMeg2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_CLEFAIRY, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_CLEFAIRY, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PainterRayna2[] = { +static const struct TrainerMon sParty_PainterRayna2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_SMEARGLE, .moves = {MOVE_CROSS_CHOP, MOVE_MEGAHORN, MOVE_DOUBLE_EDGE, MOVE_SELF_DESTRUCT}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungsterDestin2[] = { +static const struct TrainerMon sParty_YoungsterDestin2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 53, .species = SPECIES_RATICATE, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 53, .species = SPECIES_PIDGEOT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PkmnBreederAlize2[] = { +static const struct TrainerMon sParty_PkmnBreederAlize2[] = { { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 53, .species = SPECIES_PIKACHU, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 53, .species = SPECIES_CLEFAIRY, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 53, .species = SPECIES_MARILL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungCoupleGiaJes2[] = { +static const struct TrainerMon sParty_YoungCoupleGiaJes2[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_NIDORINA, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 30, .species = SPECIES_NIDORINO, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_YoungCoupleGiaJes3[] = { +static const struct TrainerMon sParty_YoungCoupleGiaJes3[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_NIDOKING, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_NIDOQUEEN, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperMilo2[] = { +static const struct TrainerMon sParty_BirdKeeperMilo2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 53, .species = SPECIES_PIDGEOTTO, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_PIDGEOT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperChaz2[] = { +static const struct TrainerMon sParty_BirdKeeperChaz2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 53, .species = SPECIES_FEAROW, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_FEAROW, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BirdKeeperHarold2[] = { +static const struct TrainerMon sParty_BirdKeeperHarold2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 53, .species = SPECIES_NOCTOWL, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_NOCTOWL, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleNicole2[] = { +static const struct TrainerMon sParty_SwimmerFemaleNicole2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_MARILL, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PsychicJaclyn2[] = { +static const struct TrainerMon sParty_PsychicJaclyn2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 52, .species = SPECIES_NATU, .moves = {MOVE_PSYCHIC, MOVE_CONFUSE_RAY, MOVE_FUTURE_SIGHT, MOVE_WISH}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 52, .species = SPECIES_SLOWBRO, .moves = {MOVE_PSYCHIC, MOVE_HEADBUTT, MOVE_AMNESIA, MOVE_YAWN}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 54, .species = SPECIES_KADABRA, .moves = {MOVE_PSYCHIC, MOVE_FUTURE_SIGHT, MOVE_RECOVER, MOVE_REFLECT}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleSamir2[] = { +static const struct TrainerMon sParty_SwimmerMaleSamir2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 55, .species = SPECIES_GYARADOS, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_HikerEarl2[] = { +static const struct TrainerMon sParty_HikerEarl2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_ONIX, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_MACHAMP, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_RuinManiacLarry2[] = { +static const struct TrainerMon sParty_RuinManiacLarry2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_MACHOKE, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_MACHOKE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_PokemaniacHector2[] = { +static const struct TrainerMon sParty_PokemaniacHector2[] = { { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 55, .species = SPECIES_RHYDON, }, { - .iv = 150, + .iv = TRAINER_PARTY_IVS(18, 18, 18, 18, 18, 18), .lvl = 55, .species = SPECIES_KANGASKHAN, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PsychicDario2[] = { +static const struct TrainerMon sParty_PsychicDario2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 56, .species = SPECIES_GIRAFARIG, .moves = {MOVE_CRUNCH, MOVE_PSYBEAM, MOVE_ODOR_SLEUTH, MOVE_AGILITY}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PsychicRodette2[] = { +static const struct TrainerMon sParty_PsychicRodette2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 53, .species = SPECIES_NATU, .moves = {MOVE_PSYCHIC, MOVE_CONFUSE_RAY, MOVE_WISH, MOVE_FUTURE_SIGHT}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 53, .species = SPECIES_HYPNO, .moves = {MOVE_PSYCHIC, MOVE_DISABLE, MOVE_PSYCH_UP, MOVE_FUTURE_SIGHT}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 53, .species = SPECIES_HYPNO, .moves = {MOVE_PSYCHIC, MOVE_HYPNOSIS, MOVE_PSYCH_UP, MOVE_FUTURE_SIGHT}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_JugglerMason2[] = { +static const struct TrainerMon sParty_JugglerMason2[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_ELECTRODE, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_PINECO, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_ELECTRODE, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 52, .species = SPECIES_PINECO, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PkmnRangerNicolas2[] = { +static const struct TrainerMon sParty_PkmnRangerNicolas2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_VICTREEBEL, .moves = {MOVE_RAZOR_LEAF, MOVE_ACID, MOVE_STUN_SPORE, MOVE_WRAP}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_VICTREEBEL, .moves = {MOVE_RAZOR_LEAF, MOVE_ACID, MOVE_SLEEP_POWDER, MOVE_SLAM}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PkmnRangerMadeline2[] = { +static const struct TrainerMon sParty_PkmnRangerMadeline2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_VILEPLUME, .moves = {MOVE_PETAL_DANCE, MOVE_MOONLIGHT, MOVE_ACID, MOVE_SLEEP_POWDER}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_VILEPLUME, .moves = {MOVE_PETAL_DANCE, MOVE_MOONLIGHT, MOVE_ACID, MOVE_STUN_SPORE}, }, }; -static const struct TrainerMonItemDefaultMoves sParty_CrushGirlCyndy2[] = { +static const struct TrainerMon sParty_CrushGirlCyndy2[] = { { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 54, .species = SPECIES_PRIMEAPE, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 54, .species = SPECIES_HITMONTOP, .heldItem = ITEM_BLACK_BELT, }, { - .iv = 170, + .iv = TRAINER_PARTY_IVS(20, 20, 20, 20, 20, 20), .lvl = 54, .species = SPECIES_MACHAMP, .heldItem = ITEM_BLACK_BELT, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TamerEvan2[] = { +static const struct TrainerMon sParty_TamerEvan2[] = { { - .iv = 160, + .iv = TRAINER_PARTY_IVS(19, 19, 19, 19, 19, 19), .lvl = 52, .species = SPECIES_SANDSLASH, }, { - .iv = 160, + .iv = TRAINER_PARTY_IVS(19, 19, 19, 19, 19, 19), .lvl = 52, .species = SPECIES_LICKITUNG, }, { - .iv = 160, + .iv = TRAINER_PARTY_IVS(19, 19, 19, 19, 19, 19), .lvl = 55, .species = SPECIES_URSARING, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PkmnRangerJackson2[] = { +static const struct TrainerMon sParty_PkmnRangerJackson2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 53, .species = SPECIES_TANGELA, .moves = {MOVE_SLAM, MOVE_MEGA_DRAIN, MOVE_BIND, MOVE_INGRAIN}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 54, .species = SPECIES_EXEGGUTOR, .moves = {MOVE_CONFUSION, MOVE_EGG_BOMB, MOVE_STUN_SPORE, MOVE_REFLECT}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_EXEGGUTOR, .moves = {MOVE_CONFUSION, MOVE_EGG_BOMB, MOVE_SLEEP_POWDER, MOVE_STOMP}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_PkmnRangerKatelyn2[] = { +static const struct TrainerMon sParty_PkmnRangerKatelyn2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 56, .species = SPECIES_CHANSEY, .moves = {MOVE_EGG_BOMB, MOVE_DEFENSE_CURL, MOVE_MINIMIZE, MOVE_SOFT_BOILED}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerLeroy2[] = { +static const struct TrainerMon sParty_CooltrainerLeroy2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 52, .species = SPECIES_RHYDON, .moves = {MOVE_EARTHQUAKE, MOVE_HORN_DRILL, MOVE_ROCK_BLAST, MOVE_SCARY_FACE}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 54, .species = SPECIES_SLOWBRO, .moves = {MOVE_PSYCHIC, MOVE_HEADBUTT, MOVE_AMNESIA, MOVE_DISABLE}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 52, .species = SPECIES_KANGASKHAN, .moves = {MOVE_DIZZY_PUNCH, MOVE_BITE, MOVE_ENDURE, MOVE_REVERSAL}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 52, .species = SPECIES_MACHAMP, .moves = {MOVE_CROSS_CHOP, MOVE_VITAL_THROW, MOVE_REVENGE, MOVE_SEISMIC_TOSS}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 55, .species = SPECIES_URSARING, .moves = {MOVE_SLASH, MOVE_FAINT_ATTACK, MOVE_SNORE, MOVE_REST}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CooltrainerMichelle2[] = { +static const struct TrainerMon sParty_CooltrainerMichelle2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 53, .species = SPECIES_PERSIAN, .moves = {MOVE_SLASH, MOVE_SCREECH, MOVE_FAINT_ATTACK, MOVE_BITE}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 53, .species = SPECIES_DEWGONG, .moves = {MOVE_ICE_BEAM, MOVE_TAKE_DOWN, MOVE_ICY_WIND, MOVE_SHEER_COLD}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 54, .species = SPECIES_NINETALES, .moves = {MOVE_FLAMETHROWER, MOVE_CONFUSE_RAY, MOVE_WILL_O_WISP, MOVE_GRUDGE}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 54, .species = SPECIES_RAPIDASH, .moves = {MOVE_BOUNCE, MOVE_AGILITY, MOVE_FIRE_SPIN, MOVE_TAKE_DOWN}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 56, .species = SPECIES_GIRAFARIG, .moves = {MOVE_CRUNCH, MOVE_PSYBEAM, MOVE_STOMP, MOVE_ODOR_SLEUTH}, }, }; -static const struct TrainerMonNoItemCustomMoves sParty_CoolCoupleLexNya2[] = { +static const struct TrainerMon sParty_CoolCoupleLexNya2[] = { { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 57, .species = SPECIES_MILTANK, .moves = {MOVE_BODY_SLAM, MOVE_MILK_DRINK, MOVE_GROWL, MOVE_DEFENSE_CURL}, }, { - .iv = 220, + .iv = TRAINER_PARTY_IVS(26, 26, 26, 26, 26, 26), .lvl = 57, .species = SPECIES_TAUROS, .moves = {MOVE_TAKE_DOWN, MOVE_SCARY_FACE, MOVE_PURSUIT, MOVE_SWAGGER}, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherColton2[] = { +static const struct TrainerMon sParty_BugCatcherColton2[] = { { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 19, .species = SPECIES_METAPOD, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 19, .species = SPECIES_WEEDLE, }, { - .iv = 20, + .iv = TRAINER_PARTY_IVS(2, 2, 2, 2, 2, 2), .lvl = 19, .species = SPECIES_METAPOD, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherColton3[] = { +static const struct TrainerMon sParty_BugCatcherColton3[] = { { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_BUTTERFREE, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_KAKUNA, }, { - .iv = 60, + .iv = TRAINER_PARTY_IVS(7, 7, 7, 7, 7, 7), .lvl = 27, .species = SPECIES_BUTTERFREE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_BugCatcherColton4[] = { +static const struct TrainerMon sParty_BugCatcherColton4[] = { { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 51, .species = SPECIES_BUTTERFREE, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 54, .species = SPECIES_BEEDRILL, }, { - .iv = 120, + .iv = TRAINER_PARTY_IVS(14, 14, 14, 14, 14, 14), .lvl = 51, .species = SPECIES_BUTTERFREE, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleMatthew2[] = { +static const struct TrainerMon sParty_SwimmerMaleMatthew2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_POLIWHIRL, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_POLIWRATH, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerMaleTony2[] = { +static const struct TrainerMon sParty_SwimmerMaleTony2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_SEADRA, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_SEADRA, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_SwimmerFemaleMelissa2[] = { +static const struct TrainerMon sParty_SwimmerFemaleMelissa2[] = { { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_POLIWHIRL, }, { - .iv = 80, + .iv = TRAINER_PARTY_IVS(9, 9, 9, 9, 9, 9), .lvl = 49, .species = SPECIES_SEAKING, }, }; -static const struct TrainerMonItemCustomMoves sParty_EliteFourLorelei2[] = { +static const struct TrainerMon sParty_EliteFourLorelei2[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 64, .species = SPECIES_DEWGONG, .heldItem = ITEM_NONE, .moves = {MOVE_ICE_BEAM, MOVE_SURF, MOVE_SIGNAL_BEAM, MOVE_DOUBLE_TEAM}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 63, .species = SPECIES_CLOYSTER, .heldItem = ITEM_NONE, .moves = {MOVE_ICE_BEAM, MOVE_SURF, MOVE_SUPERSONIC, MOVE_RAIN_DANCE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 63, .species = SPECIES_PILOSWINE, .heldItem = ITEM_NONE, .moves = {MOVE_BLIZZARD, MOVE_EARTHQUAKE, MOVE_DOUBLE_EDGE, MOVE_ROCK_SLIDE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 66, .species = SPECIES_JYNX, .heldItem = ITEM_NONE, .moves = {MOVE_ICE_BEAM, MOVE_PSYCHIC, MOVE_LOVELY_KISS, MOVE_ATTRACT}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 66, .species = SPECIES_LAPRAS, .heldItem = ITEM_CHERI_BERRY, @@ -10599,37 +9656,37 @@ static const struct TrainerMonItemCustomMoves sParty_EliteFourLorelei2[] = { }, }; -static const struct TrainerMonItemCustomMoves sParty_EliteFourBruno2[] = { +static const struct TrainerMon sParty_EliteFourBruno2[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 65, .species = SPECIES_STEELIX, .heldItem = ITEM_NONE, .moves = {MOVE_EARTHQUAKE, MOVE_IRON_TAIL, MOVE_CRUNCH, MOVE_ROCK_TOMB}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 65, .species = SPECIES_HITMONCHAN, .heldItem = ITEM_NONE, .moves = {MOVE_SKY_UPPERCUT, MOVE_MACH_PUNCH, MOVE_ROCK_SLIDE, MOVE_COUNTER}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 65, .species = SPECIES_HITMONLEE, .heldItem = ITEM_NONE, .moves = {MOVE_MEGA_KICK, MOVE_FORESIGHT, MOVE_EARTHQUAKE, MOVE_ROCK_SLIDE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 66, .species = SPECIES_STEELIX, .heldItem = ITEM_NONE, .moves = {MOVE_EARTHQUAKE, MOVE_IRON_TAIL, MOVE_CRUNCH, MOVE_DRAGON_BREATH}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 68, .species = SPECIES_MACHAMP, .heldItem = ITEM_PERSIM_BERRY, @@ -10637,37 +9694,37 @@ static const struct TrainerMonItemCustomMoves sParty_EliteFourBruno2[] = { }, }; -static const struct TrainerMonItemCustomMoves sParty_EliteFourAgatha2[] = { +static const struct TrainerMon sParty_EliteFourAgatha2[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 66, .species = SPECIES_GENGAR, .heldItem = ITEM_NONE, .moves = {MOVE_SHADOW_BALL, MOVE_PSYCHIC, MOVE_CONFUSE_RAY, MOVE_HYPNOSIS}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 66, .species = SPECIES_CROBAT, .heldItem = ITEM_NONE, .moves = {MOVE_SLUDGE_BOMB, MOVE_AIR_CUTTER, MOVE_SHADOW_BALL, MOVE_CONFUSE_RAY}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 65, .species = SPECIES_MISDREAVUS, .heldItem = ITEM_NONE, .moves = {MOVE_SHADOW_BALL, MOVE_PSYCHIC, MOVE_THUNDERBOLT, MOVE_ATTRACT}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 68, .species = SPECIES_ARBOK, .heldItem = ITEM_NONE, .moves = {MOVE_SLUDGE_BOMB, MOVE_EARTHQUAKE, MOVE_GIGA_DRAIN, MOVE_DOUBLE_TEAM}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 70, .species = SPECIES_GENGAR, .heldItem = ITEM_CHESTO_BERRY, @@ -10675,37 +9732,37 @@ static const struct TrainerMonItemCustomMoves sParty_EliteFourAgatha2[] = { }, }; -static const struct TrainerMonItemCustomMoves sParty_EliteFourLance2[] = { +static const struct TrainerMon sParty_EliteFourLance2[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 68, .species = SPECIES_GYARADOS, .heldItem = ITEM_NONE, .moves = {MOVE_HYPER_BEAM, MOVE_DRAGON_DANCE, MOVE_EARTHQUAKE, MOVE_THUNDER_WAVE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 66, .species = SPECIES_DRAGONITE, .heldItem = ITEM_NONE, .moves = {MOVE_HYPER_BEAM, MOVE_EARTHQUAKE, MOVE_DRAGON_CLAW, MOVE_FLAMETHROWER}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 66, .species = SPECIES_KINGDRA, .heldItem = ITEM_NONE, .moves = {MOVE_HYPER_BEAM, MOVE_DRAGON_DANCE, MOVE_SURF, MOVE_ICE_BEAM}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 70, .species = SPECIES_AERODACTYL, .heldItem = ITEM_NONE, .moves = {MOVE_HYPER_BEAM, MOVE_ANCIENT_POWER, MOVE_AERIAL_ACE, MOVE_EARTHQUAKE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 72, .species = SPECIES_DRAGONITE, .heldItem = ITEM_PERSIM_BERRY, @@ -10713,44 +9770,44 @@ static const struct TrainerMonItemCustomMoves sParty_EliteFourLance2[] = { }, }; -static const struct TrainerMonItemCustomMoves sParty_ChampionRematchSquirtle[] = { +static const struct TrainerMon sParty_ChampionRematchSquirtle[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 72, .species = SPECIES_HERACROSS, .heldItem = ITEM_NONE, .moves = {MOVE_MEGAHORN, MOVE_EARTHQUAKE, MOVE_COUNTER, MOVE_ROCK_TOMB}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 73, .species = SPECIES_ALAKAZAM, .heldItem = ITEM_NONE, .moves = {MOVE_PSYCHIC, MOVE_SHADOW_BALL, MOVE_CALM_MIND, MOVE_REFLECT}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 72, .species = SPECIES_TYRANITAR, .heldItem = ITEM_NONE, .moves = {MOVE_CRUNCH, MOVE_EARTHQUAKE, MOVE_THUNDERBOLT, MOVE_AERIAL_ACE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 73, .species = SPECIES_ARCANINE, .heldItem = ITEM_NONE, .moves = {MOVE_EXTREME_SPEED, MOVE_OVERHEAT, MOVE_AERIAL_ACE, MOVE_IRON_TAIL}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 73, .species = SPECIES_EXEGGUTOR, .heldItem = ITEM_NONE, .moves = {MOVE_GIGA_DRAIN, MOVE_PSYCHIC, MOVE_SLEEP_POWDER, MOVE_LIGHT_SCREEN}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 75, .species = SPECIES_BLASTOISE, .heldItem = ITEM_SITRUS_BERRY, @@ -10758,44 +9815,44 @@ static const struct TrainerMonItemCustomMoves sParty_ChampionRematchSquirtle[] = }, }; -static const struct TrainerMonItemCustomMoves sParty_ChampionRematchBulbasaur[] = { +static const struct TrainerMon sParty_ChampionRematchBulbasaur[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 72, .species = SPECIES_HERACROSS, .heldItem = ITEM_NONE, .moves = {MOVE_MEGAHORN, MOVE_EARTHQUAKE, MOVE_COUNTER, MOVE_ROCK_TOMB}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 73, .species = SPECIES_ALAKAZAM, .heldItem = ITEM_NONE, .moves = {MOVE_PSYCHIC, MOVE_SHADOW_BALL, MOVE_CALM_MIND, MOVE_REFLECT}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 72, .species = SPECIES_TYRANITAR, .heldItem = ITEM_NONE, .moves = {MOVE_CRUNCH, MOVE_EARTHQUAKE, MOVE_THUNDERBOLT, MOVE_AERIAL_ACE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 73, .species = SPECIES_GYARADOS, .heldItem = ITEM_NONE, .moves = {MOVE_HYDRO_PUMP, MOVE_DRAGON_DANCE, MOVE_EARTHQUAKE, MOVE_HYPER_BEAM}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 73, .species = SPECIES_ARCANINE, .heldItem = ITEM_NONE, .moves = {MOVE_EXTREME_SPEED, MOVE_OVERHEAT, MOVE_AERIAL_ACE, MOVE_IRON_TAIL}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 75, .species = SPECIES_VENUSAUR, .heldItem = ITEM_SITRUS_BERRY, @@ -10803,44 +9860,44 @@ static const struct TrainerMonItemCustomMoves sParty_ChampionRematchBulbasaur[] }, }; -static const struct TrainerMonItemCustomMoves sParty_ChampionRematchCharmander[] = { +static const struct TrainerMon sParty_ChampionRematchCharmander[] = { { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 72, .species = SPECIES_HERACROSS, .heldItem = ITEM_NONE, .moves = {MOVE_MEGAHORN, MOVE_EARTHQUAKE, MOVE_COUNTER, MOVE_ROCK_TOMB}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 73, .species = SPECIES_ALAKAZAM, .heldItem = ITEM_NONE, .moves = {MOVE_PSYCHIC, MOVE_SHADOW_BALL, MOVE_CALM_MIND, MOVE_REFLECT}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 72, .species = SPECIES_TYRANITAR, .heldItem = ITEM_NONE, .moves = {MOVE_CRUNCH, MOVE_EARTHQUAKE, MOVE_THUNDERBOLT, MOVE_AERIAL_ACE}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 73, .species = SPECIES_EXEGGUTOR, .heldItem = ITEM_NONE, .moves = {MOVE_GIGA_DRAIN, MOVE_PSYCHIC, MOVE_SLEEP_POWDER, MOVE_LIGHT_SCREEN}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 73, .species = SPECIES_GYARADOS, .heldItem = ITEM_NONE, .moves = {MOVE_HYDRO_PUMP, MOVE_DRAGON_DANCE, MOVE_EARTHQUAKE, MOVE_HYPER_BEAM}, }, { - .iv = 255, + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 75, .species = SPECIES_CHARIZARD, .heldItem = ITEM_SITRUS_BERRY, @@ -10848,32 +9905,29 @@ static const struct TrainerMonItemCustomMoves sParty_ChampionRematchCharmander[] }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_CueBallPaxton[] = { +static const struct TrainerMon sParty_CueBallPaxton[] = { { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 39, .species = SPECIES_WEEZING, }, { - .iv = 50, + .iv = TRAINER_PARTY_IVS(6, 6, 6, 6, 6, 6), .lvl = 39, .species = SPECIES_MUK, }, }; -static const struct TrainerMonNoItemDefaultMoves sParty_TestBattle[] = { +static const struct TrainerMon sParty_TestBattle[] = { { - .iv = 0, .lvl = 14, .species = SPECIES_VENUSAUR, }, { - .iv = 0, .lvl = 14, .species = SPECIES_CHARIZARD, }, { - .iv = 0, .lvl = 14, .species = SPECIES_BLASTOISE, }, diff --git a/src/data/trainers.h b/src/data/trainers.h index 1fe2bb969..66aca8088 100644 --- a/src/data/trainers.h +++ b/src/data/trainers.h @@ -9,8 +9,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_AquaLeader), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_AquaLeader), }, [TRAINER_AQUA_GRUNT_M] = { .trainerClass = TRAINER_CLASS_TEAM_AQUA, @@ -19,8 +19,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_AquaGruntM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_AquaGruntM), }, [TRAINER_AQUA_GRUNT_F] = { .trainerClass = TRAINER_CLASS_TEAM_AQUA, @@ -29,8 +29,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_AquaGruntF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_AquaGruntF), }, [TRAINER_RS_AROMA_LADY] = { .trainerClass = TRAINER_CLASS_RS_AROMA_LADY, @@ -39,8 +39,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSAromaLady), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSAromaLady), }, [TRAINER_RS_RUIN_MANIAC] = { .trainerClass = TRAINER_CLASS_RS_RUIN_MANIAC, @@ -49,8 +49,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSRuinManiac), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSRuinManiac), }, [TRAINER_INTERVIEWER] = { .trainerClass = TRAINER_CLASS_INTERVIEWER, @@ -59,8 +59,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Interviewer), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Interviewer), }, [TRAINER_RS_TUBER_F] = { .trainerClass = TRAINER_CLASS_RS_TUBER_F, @@ -69,8 +69,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSTuberF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSTuberF), }, [TRAINER_RS_TUBER_M] = { .trainerClass = TRAINER_CLASS_RS_TUBER_M, @@ -79,8 +79,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSTuberM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSTuberM), }, [TRAINER_RS_COOLTRAINER_M] = { .trainerClass = TRAINER_CLASS_RS_COOLTRAINER, @@ -89,8 +89,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSCooltrainerM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RSCooltrainerM), }, [TRAINER_RS_COOLTRAINER_F] = { .trainerClass = TRAINER_CLASS_RS_COOLTRAINER, @@ -99,8 +99,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSCooltrainerF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RSCooltrainerF), }, [TRAINER_HEX_MANIAC] = { .trainerClass = TRAINER_CLASS_HEX_MANIAC, @@ -109,8 +109,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HexManiac), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HexManiac), }, [TRAINER_RS_LADY] = { .trainerClass = TRAINER_CLASS_RS_LADY, @@ -119,8 +119,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSLady), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSLady), }, [TRAINER_RS_BEAUTY] = { .trainerClass = TRAINER_CLASS_RS_BEAUTY, @@ -129,8 +129,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSBeauty), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSBeauty), }, [TRAINER_RICH_BOY] = { .trainerClass = TRAINER_CLASS_RICH_BOY, @@ -139,8 +139,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RichBoy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RichBoy), }, [TRAINER_RS_POKEMANIAC] = { .trainerClass = TRAINER_CLASS_RS_POKEMANIAC, @@ -149,8 +149,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSPokemaniac), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSPokemaniac), }, [TRAINER_RS_SWIMMER_M] = { .trainerClass = TRAINER_CLASS_RS_SWIMMER_M, @@ -159,8 +159,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSSwimmerM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSSwimmerM), }, [TRAINER_RS_BLACK_BELT] = { .trainerClass = TRAINER_CLASS_RS_BLACK_BELT, @@ -169,8 +169,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSBlackBelt), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSBlackBelt), }, [TRAINER_GUITARIST] = { .trainerClass = TRAINER_CLASS_GUITARIST, @@ -179,8 +179,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Guitarist), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Guitarist), }, [TRAINER_KINDLER] = { .trainerClass = TRAINER_CLASS_KINDLER, @@ -189,8 +189,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Kindler), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Kindler), }, [TRAINER_RS_CAMPER] = { .trainerClass = TRAINER_CLASS_RS_CAMPER, @@ -199,8 +199,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSCamper), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSCamper), }, [TRAINER_BUG_MANIAC] = { .trainerClass = TRAINER_CLASS_BUG_MANIAC, @@ -209,8 +209,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugManiac), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugManiac), }, [TRAINER_RS_PSYCHIC_M] = { .trainerClass = TRAINER_CLASS_RS_PSYCHIC, @@ -219,8 +219,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSPsychicM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSPsychicM), }, [TRAINER_RS_PSYCHIC_F] = { .trainerClass = TRAINER_CLASS_RS_PSYCHIC, @@ -229,8 +229,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSPsychicF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSPsychicF), }, [TRAINER_RS_GENTLEMAN] = { .trainerClass = TRAINER_CLASS_RS_GENTLEMAN, @@ -239,8 +239,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSGentleman), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSGentleman), }, [TRAINER_ELITE_FOUR_SIDNEY] = { .trainerClass = TRAINER_CLASS_RS_ELITE_FOUR, @@ -249,8 +249,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SIDNEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_EliteFourSidney), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_EliteFourSidney), }, [TRAINER_ELITE_FOUR_PHOEBE] = { .trainerClass = TRAINER_CLASS_RS_ELITE_FOUR, @@ -259,8 +259,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PHOEBE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_EliteFourPhoebe), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_EliteFourPhoebe), }, [TRAINER_LEADER_ROXANNE] = { .trainerClass = TRAINER_CLASS_RS_LEADER, @@ -269,8 +269,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LeaderRoxanne), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LeaderRoxanne), }, [TRAINER_LEADER_BRAWLY] = { .trainerClass = TRAINER_CLASS_RS_LEADER, @@ -279,8 +279,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LeaderBrawly), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LeaderBrawly), }, [TRAINER_LEADER_TATE_LIZA] = { .trainerClass = TRAINER_CLASS_RS_LEADER, @@ -289,8 +289,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LeaderTateLiza), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LeaderTateLiza), }, [TRAINER_SCHOOL_KID_M] = { .trainerClass = TRAINER_CLASS_SCHOOL_KID, @@ -299,8 +299,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SchoolKidM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SchoolKidM), }, [TRAINER_SCHOOL_KID_F] = { .trainerClass = TRAINER_CLASS_SCHOOL_KID, @@ -309,8 +309,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SchoolKidF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SchoolKidF), }, [TRAINER_SR_AND_JR] = { .trainerClass = TRAINER_CLASS_SR_AND_JR, @@ -319,8 +319,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SrAndJr), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SrAndJr), }, [TRAINER_POKEFAN_M] = { .trainerClass = TRAINER_CLASS_POKEFAN, @@ -329,8 +329,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokefanM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokefanM), }, [TRAINER_POKEFAN_F] = { .trainerClass = TRAINER_CLASS_POKEFAN, @@ -339,8 +339,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokefanF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokefanF), }, [TRAINER_EXPERT_M] = { .trainerClass = TRAINER_CLASS_EXPERT, @@ -349,8 +349,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ExpertM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ExpertM), }, [TRAINER_EXPERT_F] = { .trainerClass = TRAINER_CLASS_EXPERT, @@ -359,8 +359,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ExpertF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ExpertF), }, [TRAINER_RS_YOUNGSTER] = { .trainerClass = TRAINER_CLASS_RS_YOUNGSTER, @@ -369,8 +369,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSYoungster), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSYoungster), }, [TRAINER_RS_CHAMPION] = { .trainerClass = TRAINER_CLASS_RS_CHAMPION, @@ -379,8 +379,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSChampion), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RSChampion), }, [TRAINER_RS_FISHERMAN] = { .trainerClass = TRAINER_CLASS_RS_FISHERMAN, @@ -389,8 +389,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSFisherman), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSFisherman), }, [TRAINER_CYCLING_TRIATHLETE_M] = { .trainerClass = TRAINER_CLASS_TRIATHLETE, @@ -399,8 +399,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CyclingTriathleteM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CyclingTriathleteM), }, [TRAINER_CYCLING_TRIATHLETE_F] = { .trainerClass = TRAINER_CLASS_TRIATHLETE, @@ -409,8 +409,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CyclingTriathleteF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CyclingTriathleteF), }, [TRAINER_RUNNING_TRIATHLETE_M] = { .trainerClass = TRAINER_CLASS_TRIATHLETE, @@ -419,8 +419,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RunningTriathleteM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RunningTriathleteM), }, [TRAINER_RUNNING_TRIATHLETE_F] = { .trainerClass = TRAINER_CLASS_TRIATHLETE, @@ -429,8 +429,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RunningTriathleteF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RunningTriathleteF), }, [TRAINER_SWIMMING_TRIATHLETE_M] = { .trainerClass = TRAINER_CLASS_TRIATHLETE, @@ -439,8 +439,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmingTriathleteM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmingTriathleteM), }, [TRAINER_SWIMMING_TRIATHLETE_F] = { .trainerClass = TRAINER_CLASS_TRIATHLETE, @@ -449,8 +449,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmingTriathleteF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmingTriathleteF), }, [TRAINER_DRAGON_TAMER] = { .trainerClass = TRAINER_CLASS_DRAGON_TAMER, @@ -459,8 +459,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_DragonTamer), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_DragonTamer), }, [TRAINER_RS_BIRD_KEEPER] = { .trainerClass = TRAINER_CLASS_RS_BIRD_KEEPER, @@ -469,8 +469,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSBirdKeeper), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSBirdKeeper), }, [TRAINER_NINJA_BOY] = { .trainerClass = TRAINER_CLASS_NINJA_BOY, @@ -479,8 +479,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_NinjaBoy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_NinjaBoy), }, [TRAINER_BATTLE_GIRL] = { .trainerClass = TRAINER_CLASS_BATTLE_GIRL, @@ -489,8 +489,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BattleGirl), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BattleGirl), }, [TRAINER_PARASOL_LADY] = { .trainerClass = TRAINER_CLASS_PARASOL_LADY, @@ -499,8 +499,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ParasolLady), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ParasolLady), }, [TRAINER_RS_SWIMMER_F] = { .trainerClass = TRAINER_CLASS_RS_SWIMMER_F, @@ -509,8 +509,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSSwimmerF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSSwimmerF), }, [TRAINER_RS_PICNICKER] = { .trainerClass = TRAINER_CLASS_RS_PICNICKER, @@ -519,8 +519,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSPicnicker), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSPicnicker), }, [TRAINER_RS_TWINS] = { .trainerClass = TRAINER_CLASS_RS_TWINS, @@ -529,8 +529,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSTwins), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSTwins), }, [TRAINER_RS_SAILOR] = { .trainerClass = TRAINER_CLASS_RS_SAILOR, @@ -539,8 +539,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSSailor), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSSailor), }, [TRAINER_BOARDER_M] = { .trainerClass = TRAINER_CLASS_BOARDER, @@ -549,8 +549,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BoarderM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BoarderM), }, [TRAINER_BOARDER_F] = { .trainerClass = TRAINER_CLASS_BOARDER, @@ -559,8 +559,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BoarderF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BoarderF), }, [TRAINER_COLLECTOR] = { .trainerClass = TRAINER_CLASS_COLLECTOR, @@ -569,8 +569,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Collector), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Collector), }, [TRAINER_WALLY] = { .trainerClass = TRAINER_CLASS_PKMN_TRAINER, @@ -579,8 +579,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Wally), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Wally), }, [TRAINER_BRENDAN] = { .trainerClass = TRAINER_CLASS_PKMN_TRAINER, @@ -589,8 +589,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Brendan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Brendan), }, [TRAINER_BRENDAN_2] = { .trainerClass = TRAINER_CLASS_PKMN_TRAINER, @@ -599,8 +599,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Brendan2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Brendan2), }, [TRAINER_BRENDAN_3] = { .trainerClass = TRAINER_CLASS_PKMN_TRAINER, @@ -609,8 +609,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Brendan3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Brendan3), }, [TRAINER_MAY] = { .trainerClass = TRAINER_CLASS_PKMN_TRAINER, @@ -619,8 +619,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_May), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_May), }, [TRAINER_MAY_2] = { .trainerClass = TRAINER_CLASS_PKMN_TRAINER, @@ -629,8 +629,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_May2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_May2), }, [TRAINER_MAY_3] = { .trainerClass = TRAINER_CLASS_PKMN_TRAINER, @@ -639,8 +639,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_May3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_May3), }, [TRAINER_RS_PKMN_BREEDER_M] = { .trainerClass = TRAINER_CLASS_RS_PKMN_BREEDER, @@ -649,8 +649,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSPkmnBreederM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSPkmnBreederM), }, [TRAINER_RS_PKMN_BREEDER_F] = { .trainerClass = TRAINER_CLASS_RS_PKMN_BREEDER, @@ -659,8 +659,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSPkmnBreederF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSPkmnBreederF), }, [TRAINER_RS_PKMN_RANGER_M] = { .trainerClass = TRAINER_CLASS_RS_PKMN_RANGER, @@ -669,8 +669,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSPkmnRangerM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RSPkmnRangerM), }, [TRAINER_RS_PKMN_RANGER_F] = { .trainerClass = TRAINER_CLASS_RS_PKMN_RANGER, @@ -679,8 +679,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSPkmnRangerF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RSPkmnRangerF), }, [TRAINER_MAGMA_LEADER] = { .trainerClass = TRAINER_CLASS_MAGMA_LEADER, @@ -689,8 +689,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_MagmaLeader), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_MagmaLeader), }, [TRAINER_MAGMA_GRUNT_M] = { .trainerClass = TRAINER_CLASS_TEAM_MAGMA, @@ -699,8 +699,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_MagmaGruntM), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_MagmaGruntM), }, [TRAINER_MAMGA_GRUNT_F] = { .trainerClass = TRAINER_CLASS_TEAM_MAGMA, @@ -709,8 +709,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_MagmaGruntF), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_MagmaGruntF), }, [TRAINER_RS_LASS] = { .trainerClass = TRAINER_CLASS_RS_LASS, @@ -719,8 +719,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSLass), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSLass), }, [TRAINER_RS_BUG_CATCHER] = { .trainerClass = TRAINER_CLASS_RS_BUG_CATCHER, @@ -729,8 +729,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSBugCatcher), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSBugCatcher), }, [TRAINER_RS_HIKER] = { .trainerClass = TRAINER_CLASS_RS_HIKER, @@ -739,8 +739,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSHiker), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSHiker), }, [TRAINER_RS_YOUNG_COUPLE] = { .trainerClass = TRAINER_CLASS_RS_YOUNG_COUPLE, @@ -749,8 +749,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSYoungCouple), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSYoungCouple), }, [TRAINER_OLD_COUPLE] = { .trainerClass = TRAINER_CLASS_OLD_COUPLE, @@ -759,8 +759,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_OldCouple), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_OldCouple), }, [TRAINER_RS_SIS_AND_BRO] = { .trainerClass = TRAINER_CLASS_RS_SIS_AND_BRO, @@ -769,8 +769,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RSSisAndBro), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RSSisAndBro), }, [TRAINER_AQUA_ADMIN_MATT] = { .trainerClass = TRAINER_CLASS_AQUA_ADMIN, @@ -779,8 +779,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MATT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_AquaAdminMatt), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_AquaAdminMatt), }, [TRAINER_AQUA_ADMIN_SHELLY] = { .trainerClass = TRAINER_CLASS_AQUA_ADMIN, @@ -789,8 +789,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_AquaAdminShelly), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_AquaAdminShelly), }, [TRAINER_MAGMA_ADMIN_TABITHA] = { .trainerClass = TRAINER_CLASS_MAGMA_ADMIN, @@ -799,8 +799,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TABITHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_MagmaAdminTabitha), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_MagmaAdminTabitha), }, [TRAINER_MAGMA_ADMIN_COURTNEY] = { .trainerClass = TRAINER_CLASS_MAGMA_ADMIN, @@ -809,8 +809,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COURTNEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_MagmaAdminCourtney), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_MagmaAdminCourtney), }, [TRAINER_LEADER_WATTSON] = { .trainerClass = TRAINER_CLASS_RS_LEADER, @@ -819,8 +819,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LeaderWattson), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LeaderWattson), }, [TRAINER_LEADER_FLANNERY] = { .trainerClass = TRAINER_CLASS_RS_LEADER, @@ -829,8 +829,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LeaderFlannery), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LeaderFlannery), }, [TRAINER_LEADER_NORMAN] = { .trainerClass = TRAINER_CLASS_RS_LEADER, @@ -839,8 +839,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LeaderNorman), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LeaderNorman), }, [TRAINER_LEADER_WINONA] = { .trainerClass = TRAINER_CLASS_RS_LEADER, @@ -849,8 +849,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LeaderWinona), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LeaderWinona), }, [TRAINER_LEADER_WALLACE] = { .trainerClass = TRAINER_CLASS_RS_LEADER, @@ -859,8 +859,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLACE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LeaderWallace), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LeaderWallace), }, [TRAINER_ELITE_FOUR_GLACIA] = { .trainerClass = TRAINER_CLASS_RS_ELITE_FOUR, @@ -869,8 +869,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GLACIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_EliteFourGlacia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_EliteFourGlacia), }, [TRAINER_ELITE_FOUR_DRAKE] = { .trainerClass = TRAINER_CLASS_RS_ELITE_FOUR, @@ -879,8 +879,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DRAKE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_EliteFourDrake), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_EliteFourDrake), }, [TRAINER_YOUNGSTER_BEN] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -889,8 +889,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterBen), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterBen), }, [TRAINER_YOUNGSTER_CALVIN] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -899,8 +899,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CALVIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterCalvin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterCalvin), }, [TRAINER_YOUNGSTER_JOSH] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -909,8 +909,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOSH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterJosh), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterJosh), }, [TRAINER_YOUNGSTER_TIMMY] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -919,8 +919,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterTimmy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterTimmy), }, [TRAINER_YOUNGSTER_JOEY] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -929,8 +929,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterJoey), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterJoey), }, [TRAINER_YOUNGSTER_DAN] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -939,8 +939,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterDan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterDan), }, [TRAINER_YOUNGSTER_CHAD] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -949,8 +949,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHAD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterChad), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterChad), }, [TRAINER_YOUNGSTER_TYLER] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -959,8 +959,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TYLER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterTyler), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterTyler), }, [TRAINER_YOUNGSTER_EDDIE] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -969,8 +969,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDDIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterEddie), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterEddie), }, [TRAINER_YOUNGSTER_DILLON] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -979,8 +979,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DILLON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterDillon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterDillon), }, [TRAINER_YOUNGSTER_YASU] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -989,8 +989,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("YASU"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterYasu), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterYasu), }, [TRAINER_YOUNGSTER_DAVE] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -999,8 +999,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAVE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterDave), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterDave), }, [TRAINER_YOUNGSTER_BEN_2] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -1009,8 +1009,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterBen2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterBen2), }, [TRAINER_BUG_CATCHER_RICK] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1019,8 +1019,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherRick), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherRick), }, [TRAINER_BUG_CATCHER_DOUG] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1029,8 +1029,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DOUG"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherDoug), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherDoug), }, [TRAINER_BUG_CATCHER_SAMMY] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1039,8 +1039,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherSammy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherSammy), }, [TRAINER_BUG_CATCHER_COLTON] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1049,8 +1049,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COLTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherColton), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherColton), }, [TRAINER_BUG_CATCHER_GREG] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1059,8 +1059,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GREG"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherGreg), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherGreg), }, [TRAINER_BUG_CATCHER_JAMES] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1069,8 +1069,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAMES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherJames), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherJames), }, [TRAINER_BUG_CATCHER_KENT] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1079,8 +1079,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherKent), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherKent), }, [TRAINER_BUG_CATCHER_ROBBY] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1089,8 +1089,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherRobby), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherRobby), }, [TRAINER_BUG_CATCHER_CALE] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1099,8 +1099,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CALE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherCale), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherCale), }, [TRAINER_BUG_CATCHER_KEIGO] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1109,8 +1109,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KEIGO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherKeigo), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherKeigo), }, [TRAINER_BUG_CATCHER_ELIJAH] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1119,8 +1119,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELIJAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherElijah), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherElijah), }, [TRAINER_BUG_CATCHER_2] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1129,8 +1129,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcher2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcher2), }, [TRAINER_BUG_CATCHER_BRENT] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1139,8 +1139,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherBrent), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherBrent), }, [TRAINER_BUG_CATCHER_CONNER] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -1149,8 +1149,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CONNER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherConner), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherConner), }, [TRAINER_LASS_JANICE] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1159,8 +1159,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JANICE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassJanice), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassJanice), }, [TRAINER_LASS_SALLY] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1169,8 +1169,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SALLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassSally), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassSally), }, [TRAINER_LASS_ROBIN] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1179,8 +1179,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassRobin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassRobin), }, [TRAINER_LASS_CRISSY] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1189,8 +1189,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISSY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassCrissy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassCrissy), }, [TRAINER_LASS_MIRIAM] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1199,8 +1199,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIRIAM"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassMiriam), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassMiriam), }, [TRAINER_LASS_IRIS] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1209,8 +1209,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("IRIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassIris), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassIris), }, [TRAINER_LASS_RELI] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1219,8 +1219,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RELI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassReli), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassReli), }, [TRAINER_LASS_ALI] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1229,8 +1229,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassAli), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassAli), }, [TRAINER_LASS_2] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1239,8 +1239,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Lass2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Lass2), }, [TRAINER_LASS_HALEY] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1249,8 +1249,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HALEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassHaley), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassHaley), }, [TRAINER_LASS_ANN] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1259,8 +1259,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassAnn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassAnn), }, [TRAINER_LASS_DAWN] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1269,8 +1269,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAWN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassDawn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassDawn), }, [TRAINER_LASS_PAIGE] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1279,8 +1279,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAIGE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassPaige), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassPaige), }, [TRAINER_LASS_ANDREA] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1289,8 +1289,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANDREA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassAndrea), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassAndrea), }, [TRAINER_LASS_MEGAN] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1299,8 +1299,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MEGAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassMegan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassMegan), }, [TRAINER_LASS_JULIA] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1309,8 +1309,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JULIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassJulia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassJulia), }, [TRAINER_LASS_KAY] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1319,8 +1319,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassKay), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassKay), }, [TRAINER_LASS_LISA] = { .trainerClass = TRAINER_CLASS_LASS, @@ -1329,8 +1329,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LISA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassLisa), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassLisa), }, [TRAINER_SAILOR_EDMOND] = { .trainerClass = TRAINER_CLASS_SAILOR, @@ -1339,8 +1339,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDMOND"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SailorEdmond), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SailorEdmond), }, [TRAINER_SAILOR_TREVOR] = { .trainerClass = TRAINER_CLASS_SAILOR, @@ -1349,8 +1349,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TREVOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SailorTrevor), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SailorTrevor), }, [TRAINER_SAILOR_LEONARD] = { .trainerClass = TRAINER_CLASS_SAILOR, @@ -1359,8 +1359,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEONARD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SailorLeonard), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SailorLeonard), }, [TRAINER_SAILOR_DUNCAN] = { .trainerClass = TRAINER_CLASS_SAILOR, @@ -1369,8 +1369,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUNCAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SailorDuncan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SailorDuncan), }, [TRAINER_SAILOR_HUEY] = { .trainerClass = TRAINER_CLASS_SAILOR, @@ -1379,8 +1379,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HUEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SailorHuey), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SailorHuey), }, [TRAINER_SAILOR_DYLAN] = { .trainerClass = TRAINER_CLASS_SAILOR, @@ -1389,8 +1389,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DYLAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SailorDylan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SailorDylan), }, [TRAINER_SAILOR_PHILLIP] = { .trainerClass = TRAINER_CLASS_SAILOR, @@ -1399,8 +1399,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PHILLIP"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SailorPhillip), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SailorPhillip), }, [TRAINER_SAILOR_DWAYNE] = { .trainerClass = TRAINER_CLASS_SAILOR, @@ -1409,8 +1409,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DWAYNE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SailorDwayne), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SailorDwayne), }, [TRAINER_CAMPER_LIAM] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -1419,8 +1419,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LIAM"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CamperLiam), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperLiam), }, [TRAINER_CAMPER_SHANE] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -1429,8 +1429,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHANE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperShane), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperShane), }, [TRAINER_CAMPER_ETHAN] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -1439,8 +1439,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ETHAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperEthan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperEthan), }, [TRAINER_CAMPER_RICKY] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -1449,8 +1449,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperRicky), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperRicky), }, [TRAINER_CAMPER_JEFF] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -1459,8 +1459,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFF"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperJeff), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperJeff), }, [TRAINER_CAMPER_2] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -1469,8 +1469,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Camper2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Camper2), }, [TRAINER_CAMPER_CHRIS] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -1479,8 +1479,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHRIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperChris), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperChris), }, [TRAINER_CAMPER_DREW] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -1489,8 +1489,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DREW"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperDrew), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperDrew), }, [TRAINER_PICNICKER_DIANA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1499,8 +1499,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DIANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerDiana), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerDiana), }, [TRAINER_PICNICKER_NANCY] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1509,8 +1509,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NANCY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerNancy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerNancy), }, [TRAINER_PICNICKER_ISABELLE] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1519,8 +1519,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerIsabelle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerIsabelle), }, [TRAINER_PICNICKER_KELSEY] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1529,8 +1529,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KELSEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerKelsey), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerKelsey), }, [TRAINER_PICNICKER_ALICIA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1539,8 +1539,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALICIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerAlicia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerAlicia), }, [TRAINER_PICNICKER_CAITLIN] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1549,8 +1549,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAITLIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerCaitlin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerCaitlin), }, [TRAINER_PICNICKER_HEIDI] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1559,8 +1559,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HEIDI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerHeidi), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerHeidi), }, [TRAINER_PICNICKER_CAROL] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1569,8 +1569,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAROL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerCarol), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerCarol), }, [TRAINER_PICNICKER_SOFIA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1579,8 +1579,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SOFIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerSofia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerSofia), }, [TRAINER_PICNICKER_MARTHA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1589,8 +1589,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARTHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerMartha), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerMartha), }, [TRAINER_PICNICKER_TINA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1599,8 +1599,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TINA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerTina), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerTina), }, [TRAINER_PICNICKER_HANNAH] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -1609,8 +1609,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HANNAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerHannah), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerHannah), }, [TRAINER_POKEMANIAC_MARK] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -1619,8 +1619,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacMark), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacMark), }, [TRAINER_POKEMANIAC_HERMAN] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -1629,8 +1629,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HERMAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacHerman), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacHerman), }, [TRAINER_POKEMANIAC_COOPER] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -1639,8 +1639,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COOPER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacCooper), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacCooper), }, [TRAINER_POKEMANIAC_STEVE] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -1649,8 +1649,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("STEVE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacSteve), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacSteve), }, [TRAINER_POKEMANIAC_WINSTON] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -1659,8 +1659,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINSTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacWinston), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacWinston), }, [TRAINER_POKEMANIAC_DAWSON] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -1669,8 +1669,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAWSON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacDawson), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacDawson), }, [TRAINER_POKEMANIAC_ASHTON] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -1679,8 +1679,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ASHTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacAshton), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacAshton), }, [TRAINER_SUPER_NERD_JOVAN] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1689,8 +1689,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOVAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerdJovan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdJovan), }, [TRAINER_SUPER_NERD_MIGUEL] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1699,8 +1699,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIGUEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerdMiguel), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdMiguel), }, [TRAINER_SUPER_NERD_AIDAN] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1709,8 +1709,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AIDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_SuperNerdAidan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdAidan), }, [TRAINER_SUPER_NERD_GLENN] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1719,8 +1719,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GLENN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerdGlenn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdGlenn), }, [TRAINER_SUPER_NERD_LESLIE] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1729,8 +1729,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LESLIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_SuperNerdLeslie), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdLeslie), }, [TRAINER_SUPER_NERD_1] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1739,8 +1739,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerd1), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerd1), }, [TRAINER_SUPER_NERD_2] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1749,8 +1749,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerd2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerd2), }, [TRAINER_SUPER_NERD_3] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1759,8 +1759,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerd3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerd3), }, [TRAINER_SUPER_NERD_ERIK] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1769,8 +1769,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERIK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerdErik), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdErik), }, [TRAINER_SUPER_NERD_AVERY] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1779,8 +1779,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AVERY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerdAvery), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdAvery), }, [TRAINER_SUPER_NERD_DEREK] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1789,8 +1789,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DEREK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerdDerek), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdDerek), }, [TRAINER_SUPER_NERD_ZAC] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -1799,8 +1799,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ZAC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerdZac), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdZac), }, [TRAINER_HIKER_MARCOS] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1809,8 +1809,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARCOS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerMarcos), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerMarcos), }, [TRAINER_HIKER_FRANKLIN] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1819,8 +1819,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("FRANKLIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerFranklin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerFranklin), }, [TRAINER_HIKER_NOB] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1829,8 +1829,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerNob), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerNob), }, [TRAINER_HIKER_WAYNE] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1839,8 +1839,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WAYNE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerWayne), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerWayne), }, [TRAINER_HIKER_ALAN] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1849,8 +1849,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_HikerAlan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerAlan), }, [TRAINER_HIKER_BRICE] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1859,8 +1859,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRICE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerBrice), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerBrice), }, [TRAINER_HIKER_CLARK] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1869,8 +1869,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CLARK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_HikerClark), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerClark), }, [TRAINER_HIKER_TRENT] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1879,8 +1879,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TRENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerTrent), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerTrent), }, [TRAINER_HIKER_DUDLEY] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1889,8 +1889,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUDLEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_HikerDudley), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerDudley), }, [TRAINER_HIKER_ALLEN] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1899,8 +1899,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALLEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_HikerAllen), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerAllen), }, [TRAINER_HIKER_ERIC] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1909,8 +1909,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERIC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerEric), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerEric), }, [TRAINER_HIKER_LENNY] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1919,8 +1919,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerLenny), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerLenny), }, [TRAINER_HIKER_OLIVER] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1929,8 +1929,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("OLIVER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerOliver), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerOliver), }, [TRAINER_HIKER_LUCAS] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -1939,8 +1939,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUCAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_HikerLucas), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerLucas), }, [TRAINER_BIKER_JARED] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -1949,8 +1949,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JARED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerJared), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerJared), }, [TRAINER_BIKER_MALIK] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -1959,8 +1959,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MALIK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerMalik), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerMalik), }, [TRAINER_BIKER_ERNEST] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -1969,8 +1969,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERNEST"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerErnest), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerErnest), }, [TRAINER_BIKER_ALEX] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -1979,8 +1979,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEX"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerAlex), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerAlex), }, [TRAINER_BIKER_LAO] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -1989,8 +1989,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerLao), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerLao), }, [TRAINER_BIKER_1] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -1999,8 +1999,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Biker1), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Biker1), }, [TRAINER_BIKER_HIDEO] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -2009,8 +2009,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HIDEO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BikerHideo), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerHideo), }, [TRAINER_BIKER_RUBEN] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -2019,8 +2019,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RUBEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerRuben), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerRuben), }, [TRAINER_BIKER_BILLY] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -2029,8 +2029,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BILLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BikerBilly), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerBilly), }, [TRAINER_BIKER_NIKOLAS] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -2039,8 +2039,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NIKOLAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerNikolas), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerNikolas), }, [TRAINER_BIKER_JAXON] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -2049,8 +2049,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAXON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerJaxon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerJaxon), }, [TRAINER_BIKER_WILLIAM] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -2059,8 +2059,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILLIAM"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerWilliam), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerWilliam), }, [TRAINER_BIKER_LUKAS] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -2069,8 +2069,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUKAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerLukas), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerLukas), }, [TRAINER_BIKER_ISAAC] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -2079,8 +2079,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAAC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerIsaac), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerIsaac), }, [TRAINER_BIKER_GERALD] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -2089,8 +2089,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GERALD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerGerald), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerGerald), }, [TRAINER_BURGLAR_1] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2099,8 +2099,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Burglar1), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Burglar1), }, [TRAINER_BURGLAR_2] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2109,8 +2109,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Burglar2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Burglar2), }, [TRAINER_BURGLAR_3] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2119,8 +2119,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Burglar3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Burglar3), }, [TRAINER_BURGLAR_QUINN] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2129,8 +2129,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("QUINN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BurglarQuinn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BurglarQuinn), }, [TRAINER_BURGLAR_RAMON] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2139,8 +2139,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RAMON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BurglarRamon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BurglarRamon), }, [TRAINER_BURGLAR_DUSTY] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2149,8 +2149,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUSTY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BurglarDusty), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BurglarDusty), }, [TRAINER_BURGLAR_ARNIE] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2159,8 +2159,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ARNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BurglarArnie), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BurglarArnie), }, [TRAINER_BURGLAR_4] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2169,8 +2169,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Burglar4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Burglar4), }, [TRAINER_BURGLAR_SIMON] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2179,8 +2179,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SIMON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BurglarSimon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BurglarSimon), }, [TRAINER_BURGLAR_LEWIS] = { .trainerClass = TRAINER_CLASS_BURGLAR, @@ -2189,8 +2189,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEWIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BurglarLewis), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BurglarLewis), }, [TRAINER_ENGINEER_BAILY] = { .trainerClass = TRAINER_CLASS_ENGINEER, @@ -2199,8 +2199,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BAILY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_EngineerBaily), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_EngineerBaily), }, [TRAINER_ENGINEER_BRAXTON] = { .trainerClass = TRAINER_CLASS_ENGINEER, @@ -2209,8 +2209,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAXTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_EngineerBraxton), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_EngineerBraxton), }, [TRAINER_ENGINEER_BERNIE] = { .trainerClass = TRAINER_CLASS_ENGINEER, @@ -2219,8 +2219,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_EngineerBernie), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_EngineerBernie), }, [TRAINER_FISHERMAN_DALE] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2229,8 +2229,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DALE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanDale), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanDale), }, [TRAINER_FISHERMAN_BARNY] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2239,8 +2239,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BARNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanBarny), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanBarny), }, [TRAINER_FISHERMAN_NED] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2249,8 +2249,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanNed), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanNed), }, [TRAINER_FISHERMAN_CHIP] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2259,8 +2259,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHIP"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanChip), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanChip), }, [TRAINER_FISHERMAN_HANK] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2269,8 +2269,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HANK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanHank), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanHank), }, [TRAINER_FISHERMAN_ELLIOT] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2279,8 +2279,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELLIOT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanElliot), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanElliot), }, [TRAINER_FISHERMAN_RONALD] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2289,8 +2289,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RONALD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanRonald), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanRonald), }, [TRAINER_FISHERMAN_CLAUDE] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2299,8 +2299,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CLAUDE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanClaude), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanClaude), }, [TRAINER_FISHERMAN_WADE] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2309,8 +2309,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WADE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanWade), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanWade), }, [TRAINER_FISHERMAN_NOLAN] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2319,8 +2319,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOLAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanNolan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanNolan), }, [TRAINER_FISHERMAN_ANDREW] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -2329,8 +2329,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANDREW"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanAndrew), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanAndrew), }, [TRAINER_SWIMMER_MALE_LUIS] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2339,8 +2339,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleLuis), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleLuis), }, [TRAINER_SWIMMER_MALE_RICHARD] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2349,8 +2349,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICHARD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleRichard), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleRichard), }, [TRAINER_SWIMMER_MALE_REECE] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2359,8 +2359,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("REECE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleReece), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleReece), }, [TRAINER_SWIMMER_MALE_MATTHEW] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2369,8 +2369,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MATTHEW"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleMatthew), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleMatthew), }, [TRAINER_SWIMMER_MALE_DOUGLAS] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2379,8 +2379,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DOUGLAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleDouglas), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleDouglas), }, [TRAINER_SWIMMER_MALE_DAVID] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2389,8 +2389,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAVID"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleDavid), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleDavid), }, [TRAINER_SWIMMER_MALE_TONY] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2399,8 +2399,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TONY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleTony), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleTony), }, [TRAINER_SWIMMER_MALE_AXLE] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2409,8 +2409,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AXLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleAxle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleAxle), }, [TRAINER_SWIMMER_MALE_BARRY] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2419,8 +2419,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BARRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleBarry), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleBarry), }, [TRAINER_SWIMMER_MALE_DEAN] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2429,8 +2429,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DEAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleDean), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleDean), }, [TRAINER_SWIMMER_MALE_DARRIN] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2439,8 +2439,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARRIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleDarrin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleDarrin), }, [TRAINER_SWIMMER_MALE_SPENCER] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2449,8 +2449,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SPENCER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleSpencer), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleSpencer), }, [TRAINER_SWIMMER_MALE_JACK] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2459,8 +2459,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleJack), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleJack), }, [TRAINER_SWIMMER_MALE_JEROME] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2469,8 +2469,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEROME"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleJerome), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleJerome), }, [TRAINER_SWIMMER_MALE_ROLAND] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -2479,8 +2479,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROLAND"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleRoland), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleRoland), }, [TRAINER_CUE_BALL_KOJI] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -2489,8 +2489,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KOJI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallKoji), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallKoji), }, [TRAINER_CUE_BALL_LUKE] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -2499,8 +2499,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUKE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallLuke), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallLuke), }, [TRAINER_CUE_BALL_CAMRON] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -2509,8 +2509,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMRON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallCamron), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallCamron), }, [TRAINER_CUE_BALL_RAUL] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -2519,8 +2519,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RAUL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallRaul), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallRaul), }, [TRAINER_CUE_BALL_ISAIAH] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -2529,8 +2529,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAIAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallIsaiah), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallIsaiah), }, [TRAINER_CUE_BALL_ZEEK] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -2539,8 +2539,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ZEEK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallZeek), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallZeek), }, [TRAINER_CUE_BALL_JAMAL] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -2549,8 +2549,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAMAL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallJamal), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallJamal), }, [TRAINER_CUE_BALL_COREY] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -2559,8 +2559,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COREY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallCorey), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallCorey), }, [TRAINER_CUE_BALL_CHASE] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -2569,8 +2569,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHASE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallChase), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallChase), }, [TRAINER_GAMER_HUGO] = { .trainerClass = TRAINER_CLASS_GAMER, @@ -2579,8 +2579,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HUGO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GamerHugo), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GamerHugo), }, [TRAINER_GAMER_JASPER] = { .trainerClass = TRAINER_CLASS_GAMER, @@ -2589,8 +2589,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JASPER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GamerJasper), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GamerJasper), }, [TRAINER_GAMER_DIRK] = { .trainerClass = TRAINER_CLASS_GAMER, @@ -2599,8 +2599,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DIRK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GamerDirk), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GamerDirk), }, [TRAINER_GAMER_DARIAN] = { .trainerClass = TRAINER_CLASS_GAMER, @@ -2609,8 +2609,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARIAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GamerDarian), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GamerDarian), }, [TRAINER_GAMER_STAN] = { .trainerClass = TRAINER_CLASS_GAMER, @@ -2619,8 +2619,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("STAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GamerStan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GamerStan), }, [TRAINER_GAMER_1] = { .trainerClass = TRAINER_CLASS_GAMER, @@ -2629,8 +2629,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Gamer1), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Gamer1), }, [TRAINER_GAMER_RICH] = { .trainerClass = TRAINER_CLASS_GAMER, @@ -2639,8 +2639,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GamerRich), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GamerRich), }, [TRAINER_BEAUTY_BRIDGET] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -2649,8 +2649,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRIDGET"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautyBridget), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautyBridget), }, [TRAINER_BEAUTY_TAMIA] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -2659,8 +2659,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TAMIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautyTamia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautyTamia), }, [TRAINER_BEAUTY_LORI] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -2669,8 +2669,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LORI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautyLori), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautyLori), }, [TRAINER_BEAUTY_LOLA] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -2679,8 +2679,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LOLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautyLola), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautyLola), }, [TRAINER_BEAUTY_SHEILA] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -2689,8 +2689,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHEILA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautySheila), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautySheila), }, [TRAINER_SWIMMER_FEMALE_TIFFANY] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -2699,8 +2699,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIFFANY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleTiffany), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleTiffany), }, [TRAINER_SWIMMER_FEMALE_NORA] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -2709,8 +2709,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleNora), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleNora), }, [TRAINER_SWIMMER_FEMALE_MELISSA] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -2719,8 +2719,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MELISSA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleMelissa), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleMelissa), }, [TRAINER_BEAUTY_GRACE] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -2729,8 +2729,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRACE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautyGrace), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautyGrace), }, [TRAINER_BEAUTY_OLIVIA] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -2739,8 +2739,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("OLIVIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautyOlivia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautyOlivia), }, [TRAINER_BEAUTY_LAUREN] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -2749,8 +2749,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAUREN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautyLauren), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautyLauren), }, [TRAINER_SWIMMER_FEMALE_ANYA] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -2759,8 +2759,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANYA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleAnya), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleAnya), }, [TRAINER_SWIMMER_FEMALE_ALICE] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -2769,8 +2769,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALICE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleAlice), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleAlice), }, [TRAINER_SWIMMER_FEMALE_CONNIE] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -2779,8 +2779,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CONNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleConnie), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleConnie), }, [TRAINER_SWIMMER_FEMALE_SHIRLEY] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -2789,8 +2789,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHIRLEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleShirley), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleShirley), }, [TRAINER_PSYCHIC_JOHAN] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -2799,8 +2799,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PsychicJohan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicJohan), }, [TRAINER_PSYCHIC_TYRON] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -2809,8 +2809,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TYRON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PsychicTyron), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicTyron), }, [TRAINER_PSYCHIC_CAMERON] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -2819,8 +2819,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMERON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PsychicCameron), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicCameron), }, [TRAINER_PSYCHIC_PRESTON] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -2829,8 +2829,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PRESTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PsychicPreston), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicPreston), }, [TRAINER_ROCKER_RANDALL] = { .trainerClass = TRAINER_CLASS_ROCKER, @@ -2839,8 +2839,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RANDALL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RockerRandall), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RockerRandall), }, [TRAINER_ROCKER_LUCA] = { .trainerClass = TRAINER_CLASS_ROCKER, @@ -2849,8 +2849,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUCA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RockerLuca), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RockerLuca), }, [TRAINER_JUGGLER_DALTON] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -2859,8 +2859,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DALTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_JugglerDalton), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerDalton), }, [TRAINER_JUGGLER_NELSON] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -2869,8 +2869,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NELSON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_JugglerNelson), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerNelson), }, [TRAINER_JUGGLER_KIRK] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -2879,8 +2879,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIRK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_JugglerKirk), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerKirk), }, [TRAINER_JUGGLER_SHAWN] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -2889,8 +2889,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHAWN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_JugglerShawn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerShawn), }, [TRAINER_JUGGLER_GREGORY] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -2899,8 +2899,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GREGORY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_JugglerGregory), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerGregory), }, [TRAINER_JUGGLER_EDWARD] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -2909,8 +2909,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDWARD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_JugglerEdward), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerEdward), }, [TRAINER_JUGGLER_KAYDEN] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -2919,8 +2919,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAYDEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_JugglerKayden), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerKayden), }, [TRAINER_JUGGLER_NATE] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -2929,8 +2929,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NATE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_JugglerNate), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerNate), }, [TRAINER_TAMER_PHIL] = { .trainerClass = TRAINER_CLASS_TAMER, @@ -2939,8 +2939,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PHIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TamerPhil), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TamerPhil), }, [TRAINER_TAMER_EDGAR] = { .trainerClass = TRAINER_CLASS_TAMER, @@ -2949,8 +2949,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDGAR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TamerEdgar), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TamerEdgar), }, [TRAINER_TAMER_JASON] = { .trainerClass = TRAINER_CLASS_TAMER, @@ -2959,8 +2959,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JASON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TamerJason), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TamerJason), }, [TRAINER_TAMER_COLE] = { .trainerClass = TRAINER_CLASS_TAMER, @@ -2969,8 +2969,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TamerCole), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TamerCole), }, [TRAINER_TAMER_VINCENT] = { .trainerClass = TRAINER_CLASS_TAMER, @@ -2979,8 +2979,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("VINCENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TamerVincent), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TamerVincent), }, [TRAINER_TAMER_JOHN] = { .trainerClass = TRAINER_CLASS_TAMER, @@ -2989,8 +2989,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TamerJohn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TamerJohn), }, [TRAINER_BIRD_KEEPER_SEBASTIAN] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -2999,8 +2999,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SEBASTIAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperSebastian), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperSebastian), }, [TRAINER_BIRD_KEEPER_PERRY] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3009,8 +3009,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperPerry), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperPerry), }, [TRAINER_BIRD_KEEPER_ROBERT] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3019,8 +3019,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBERT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperRobert), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperRobert), }, [TRAINER_BIRD_KEEPER_DONALD] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3029,8 +3029,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DONALD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperDonald), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperDonald), }, [TRAINER_BIRD_KEEPER_BENNY] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3039,8 +3039,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperBenny), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperBenny), }, [TRAINER_BIRD_KEEPER_EDWIN] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3049,8 +3049,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDWIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperEdwin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperEdwin), }, [TRAINER_BIRD_KEEPER_CHESTER] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3059,8 +3059,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHESTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperChester), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperChester), }, [TRAINER_BIRD_KEEPER_WILTON] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3069,8 +3069,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperWilton), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperWilton), }, [TRAINER_BIRD_KEEPER_RAMIRO] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3079,8 +3079,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RAMIRO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperRamiro), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperRamiro), }, [TRAINER_BIRD_KEEPER_JACOB] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3089,8 +3089,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperJacob), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperJacob), }, [TRAINER_BIRD_KEEPER_ROGER] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3099,8 +3099,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROGER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperRoger), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperRoger), }, [TRAINER_BIRD_KEEPER_REED] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3109,8 +3109,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("REED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperReed), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperReed), }, [TRAINER_BIRD_KEEPER_KEITH] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3119,8 +3119,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KEITH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperKeith), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperKeith), }, [TRAINER_BIRD_KEEPER_CARTER] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3129,8 +3129,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CARTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperCarter), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperCarter), }, [TRAINER_BIRD_KEEPER_MITCH] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3139,8 +3139,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MITCH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperMitch), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperMitch), }, [TRAINER_BIRD_KEEPER_BECK] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3149,8 +3149,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BECK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperBeck), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperBeck), }, [TRAINER_BIRD_KEEPER_MARLON] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -3159,8 +3159,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARLON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperMarlon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperMarlon), }, [TRAINER_BLACK_BELT_KOICHI] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -3169,8 +3169,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KOICHI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltKoichi), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltKoichi), }, [TRAINER_BLACK_BELT_MIKE] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -3179,8 +3179,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIKE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltMike), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltMike), }, [TRAINER_BLACK_BELT_HIDEKI] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -3189,8 +3189,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HIDEKI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltHideki), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltHideki), }, [TRAINER_BLACK_BELT_AARON] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -3199,8 +3199,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AARON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltAaron), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltAaron), }, [TRAINER_BLACK_BELT_HITOSHI] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -3209,8 +3209,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HITOSHI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltHitoshi), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltHitoshi), }, [TRAINER_BLACK_BELT_ATSUSHI] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -3219,8 +3219,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ATSUSHI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltAtsushi), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltAtsushi), }, [TRAINER_BLACK_BELT_KIYO] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -3229,8 +3229,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIYO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltKiyo), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltKiyo), }, [TRAINER_BLACK_BELT_TAKASHI] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -3239,8 +3239,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TAKASHI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltTakashi), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltTakashi), }, [TRAINER_BLACK_BELT_DAISUKE] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -3249,8 +3249,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAISUKE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltDaisuke), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltDaisuke), }, [TRAINER_RIVAL_OAKS_LAB_SQUIRTLE] = { .trainerClass = TRAINER_CLASS_RIVAL_EARLY, @@ -3259,8 +3259,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalOaksLabSquirtle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalOaksLabSquirtle), }, [TRAINER_RIVAL_OAKS_LAB_BULBASAUR] = { .trainerClass = TRAINER_CLASS_RIVAL_EARLY, @@ -3269,8 +3269,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalOaksLabBulbasaur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalOaksLabBulbasaur), }, [TRAINER_RIVAL_OAKS_LAB_CHARMANDER] = { .trainerClass = TRAINER_CLASS_RIVAL_EARLY, @@ -3279,8 +3279,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalOaksLabCharmander), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalOaksLabCharmander), }, [TRAINER_RIVAL_ROUTE22_EARLY_SQUIRTLE] = { .trainerClass = TRAINER_CLASS_RIVAL_EARLY, @@ -3289,8 +3289,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RivalRoute22EarlySquirtle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalRoute22EarlySquirtle), }, [TRAINER_RIVAL_ROUTE22_EARLY_BULBASAUR] = { .trainerClass = TRAINER_CLASS_RIVAL_EARLY, @@ -3299,8 +3299,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RivalRoute22EarlyBulbasaur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalRoute22EarlyBulbasaur), }, [TRAINER_RIVAL_ROUTE22_EARLY_CHARMANDER] = { .trainerClass = TRAINER_CLASS_RIVAL_EARLY, @@ -3309,8 +3309,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RivalRoute22EarlyCharmander), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalRoute22EarlyCharmander), }, [TRAINER_RIVAL_CERULEAN_SQUIRTLE] = { .trainerClass = TRAINER_CLASS_RIVAL_EARLY, @@ -3319,8 +3319,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RivalCeruleanSquirtle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalCeruleanSquirtle), }, [TRAINER_RIVAL_CERULEAN_BULBASAUR] = { .trainerClass = TRAINER_CLASS_RIVAL_EARLY, @@ -3329,8 +3329,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RivalCeruleanBulbasaur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalCeruleanBulbasaur), }, [TRAINER_RIVAL_CERULEAN_CHARMANDER] = { .trainerClass = TRAINER_CLASS_RIVAL_EARLY, @@ -3339,8 +3339,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RivalCeruleanCharmander), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalCeruleanCharmander), }, [TRAINER_SCIENTIST_TED] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3349,8 +3349,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ScientistTed), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistTed), }, [TRAINER_SCIENTIST_CONNOR] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3359,8 +3359,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CONNOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_ScientistConnor), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistConnor), }, [TRAINER_SCIENTIST_JERRY] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3369,8 +3369,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ScientistJerry), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistJerry), }, [TRAINER_SCIENTIST_JOSE] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3379,8 +3379,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOSE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_ScientistJose), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistJose), }, [TRAINER_SCIENTIST_RODNEY] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3389,8 +3389,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RODNEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ScientistRodney), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistRodney), }, [TRAINER_SCIENTIST_BEAU] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3399,8 +3399,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BEAU"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_ScientistBeau), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistBeau), }, [TRAINER_SCIENTIST_TAYLOR] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3409,8 +3409,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TAYLOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_ScientistTaylor), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistTaylor), }, [TRAINER_SCIENTIST_JOSHUA] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3419,8 +3419,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOSHUA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ScientistJoshua), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistJoshua), }, [TRAINER_SCIENTIST_PARKER] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3429,8 +3429,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PARKER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ScientistParker), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistParker), }, [TRAINER_SCIENTIST_ED] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3439,8 +3439,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_ScientistEd), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistEd), }, [TRAINER_SCIENTIST_TRAVIS] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3449,8 +3449,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TRAVIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ScientistTravis), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistTravis), }, [TRAINER_SCIENTIST_BRAYDON] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3459,8 +3459,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAYDON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ScientistBraydon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistBraydon), }, [TRAINER_SCIENTIST_IVAN] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -3469,8 +3469,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("IVAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ScientistIvan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistIvan), }, [TRAINER_BOSS_GIOVANNI] = { .trainerClass = TRAINER_CLASS_BOSS, @@ -3479,8 +3479,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GIOVANNI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BossGiovanni), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BossGiovanni), }, [TRAINER_BOSS_GIOVANNI_2] = { .trainerClass = TRAINER_CLASS_BOSS, @@ -3489,8 +3489,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GIOVANNI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BossGiovanni2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BossGiovanni2), }, [TRAINER_LEADER_GIOVANNI] = { .trainerClass = TRAINER_CLASS_LEADER, @@ -3499,8 +3499,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GIOVANNI"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_FULL_HEAL}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_LeaderGiovanni), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_LeaderGiovanni), }, [TRAINER_TEAM_ROCKET_GRUNT] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3509,8 +3509,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt), }, [TRAINER_TEAM_ROCKET_GRUNT_2] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3519,8 +3519,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt2), }, [TRAINER_TEAM_ROCKET_GRUNT_3] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3529,8 +3529,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt3), }, [TRAINER_TEAM_ROCKET_GRUNT_4] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3539,8 +3539,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt4), }, [TRAINER_TEAM_ROCKET_GRUNT_5] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3549,8 +3549,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt5), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt5), }, [TRAINER_TEAM_ROCKET_GRUNT_6] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3559,8 +3559,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt6), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt6), }, [TRAINER_TEAM_ROCKET_GRUNT_7] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3569,8 +3569,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt7), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt7), }, [TRAINER_TEAM_ROCKET_GRUNT_8] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3579,8 +3579,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt8), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt8), }, [TRAINER_TEAM_ROCKET_GRUNT_9] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3589,8 +3589,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt9), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt9), }, [TRAINER_TEAM_ROCKET_GRUNT_10] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3599,8 +3599,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_TeamRocketGrunt10), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt10), }, [TRAINER_TEAM_ROCKET_GRUNT_11] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3609,8 +3609,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt11), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt11), }, [TRAINER_TEAM_ROCKET_GRUNT_12] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3619,8 +3619,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_TeamRocketGrunt12), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt12), }, [TRAINER_TEAM_ROCKET_GRUNT_13] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3629,8 +3629,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_TeamRocketGrunt13), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt13), }, [TRAINER_TEAM_ROCKET_GRUNT_14] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3639,8 +3639,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt14), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt14), }, [TRAINER_TEAM_ROCKET_GRUNT_15] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3649,8 +3649,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt15), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt15), }, [TRAINER_TEAM_ROCKET_GRUNT_16] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3659,8 +3659,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt16), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt16), }, [TRAINER_TEAM_ROCKET_GRUNT_17] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3669,8 +3669,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt17), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt17), }, [TRAINER_TEAM_ROCKET_GRUNT_18] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3679,8 +3679,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt18), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt18), }, [TRAINER_TEAM_ROCKET_GRUNT_19] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3689,8 +3689,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt19), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt19), }, [TRAINER_TEAM_ROCKET_GRUNT_20] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3699,8 +3699,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt20), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt20), }, [TRAINER_TEAM_ROCKET_GRUNT_21] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3709,8 +3709,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt21), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt21), }, [TRAINER_TEAM_ROCKET_GRUNT_22] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3719,8 +3719,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt22), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt22), }, [TRAINER_TEAM_ROCKET_GRUNT_23] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3729,8 +3729,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt23), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt23), }, [TRAINER_TEAM_ROCKET_GRUNT_24] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3739,8 +3739,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt24), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt24), }, [TRAINER_TEAM_ROCKET_GRUNT_25] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3749,8 +3749,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt25), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt25), }, [TRAINER_TEAM_ROCKET_GRUNT_26] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3759,8 +3759,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt26), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt26), }, [TRAINER_TEAM_ROCKET_GRUNT_27] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3769,8 +3769,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt27), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt27), }, [TRAINER_TEAM_ROCKET_GRUNT_28] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3779,8 +3779,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt28), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt28), }, [TRAINER_TEAM_ROCKET_GRUNT_29] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3789,8 +3789,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt29), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt29), }, [TRAINER_TEAM_ROCKET_GRUNT_30] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3799,8 +3799,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt30), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt30), }, [TRAINER_TEAM_ROCKET_GRUNT_31] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3809,8 +3809,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt31), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt31), }, [TRAINER_TEAM_ROCKET_GRUNT_32] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3819,8 +3819,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_TeamRocketGrunt32), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt32), }, [TRAINER_TEAM_ROCKET_GRUNT_33] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3829,8 +3829,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt33), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt33), }, [TRAINER_TEAM_ROCKET_GRUNT_34] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3839,8 +3839,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt34), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt34), }, [TRAINER_TEAM_ROCKET_GRUNT_35] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3849,8 +3849,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt35), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt35), }, [TRAINER_TEAM_ROCKET_GRUNT_36] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3859,8 +3859,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt36), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt36), }, [TRAINER_TEAM_ROCKET_GRUNT_37] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3869,8 +3869,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt37), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt37), }, [TRAINER_TEAM_ROCKET_GRUNT_38] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3879,8 +3879,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt38), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt38), }, [TRAINER_TEAM_ROCKET_GRUNT_39] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3889,8 +3889,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt39), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt39), }, [TRAINER_TEAM_ROCKET_GRUNT_40] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3899,8 +3899,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt40), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt40), }, [TRAINER_TEAM_ROCKET_GRUNT_41] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -3909,8 +3909,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt41), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt41), }, [TRAINER_COOLTRAINER_SAMUEL] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -3919,8 +3919,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAMUEL"), .items = {ITEM_SUPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerSamuel), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerSamuel), }, [TRAINER_COOLTRAINER_GEORGE] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -3929,8 +3929,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GEORGE"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerGeorge), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerGeorge), }, [TRAINER_COOLTRAINER_COLBY] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -3939,8 +3939,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COLBY"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerColby), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerColby), }, [TRAINER_COOLTRAINER_PAUL] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -3949,8 +3949,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAUL"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerPaul), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerPaul), }, [TRAINER_COOLTRAINER_ROLANDO] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -3959,8 +3959,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROLANDO"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerRolando), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerRolando), }, [TRAINER_COOLTRAINER_GILBERT] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -3969,8 +3969,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GILBERT"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerGilbert), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerGilbert), }, [TRAINER_COOLTRAINER_OWEN] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -3979,8 +3979,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("OWEN"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerOwen), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerOwen), }, [TRAINER_COOLTRAINER_BERKE] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -3989,8 +3989,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERKE"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerBerke), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerBerke), }, [TRAINER_COOLTRAINER_YUJI] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -3999,8 +3999,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("YUJI"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerYuji), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerYuji), }, [TRAINER_COOLTRAINER_WARREN] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -4009,8 +4009,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WARREN"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerWarren), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerWarren), }, [TRAINER_COOLTRAINER_MARY] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -4019,8 +4019,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARY"), .items = {ITEM_SUPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerMary), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerMary), }, [TRAINER_COOLTRAINER_CAROLINE] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -4029,8 +4029,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAROLINE"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerCaroline), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerCaroline), }, [TRAINER_COOLTRAINER_ALEXA] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -4039,8 +4039,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEXA"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerAlexa), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerAlexa), }, [TRAINER_COOLTRAINER_SHANNON] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -4049,8 +4049,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHANNON"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerShannon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerShannon), }, [TRAINER_COOLTRAINER_NAOMI] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -4059,8 +4059,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NAOMI"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerNaomi), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerNaomi), }, [TRAINER_COOLTRAINER_BROOKE] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -4069,8 +4069,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerBrooke), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerBrooke), }, [TRAINER_COOLTRAINER_AUSTINA] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -4079,8 +4079,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AUSTINA"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerAustina), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerAustina), }, [TRAINER_COOLTRAINER_JULIE] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -4089,8 +4089,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JULIE"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerJulie), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerJulie), }, [TRAINER_ELITE_FOUR_LORELEI] = { .trainerClass = TRAINER_CLASS_ELITE_FOUR, @@ -4099,8 +4099,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LORELEI"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_EliteFourLorelei), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_EliteFourLorelei), }, [TRAINER_ELITE_FOUR_BRUNO] = { .trainerClass = TRAINER_CLASS_ELITE_FOUR, @@ -4109,8 +4109,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRUNO"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_EliteFourBruno), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_EliteFourBruno), }, [TRAINER_ELITE_FOUR_AGATHA] = { .trainerClass = TRAINER_CLASS_ELITE_FOUR, @@ -4119,8 +4119,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AGATHA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_EliteFourAgatha), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_EliteFourAgatha), }, [TRAINER_ELITE_FOUR_LANCE] = { .trainerClass = TRAINER_CLASS_ELITE_FOUR, @@ -4129,8 +4129,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LANCE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_EliteFourLance), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_EliteFourLance), }, [TRAINER_LEADER_BROCK] = { .trainerClass = TRAINER_CLASS_LEADER, @@ -4139,8 +4139,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROCK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_LeaderBrock), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_LeaderBrock), }, [TRAINER_LEADER_MISTY] = { .trainerClass = TRAINER_CLASS_LEADER, @@ -4149,8 +4149,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MISTY"), .items = {ITEM_SUPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_LeaderMisty), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_LeaderMisty), }, [TRAINER_LEADER_LT_SURGE] = { .trainerClass = TRAINER_CLASS_LEADER, @@ -4159,8 +4159,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LT. SURGE"), .items = {ITEM_SUPER_POTION, ITEM_FULL_HEAL}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_LeaderLtSurge), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_LeaderLtSurge), }, [TRAINER_LEADER_ERIKA] = { .trainerClass = TRAINER_CLASS_LEADER, @@ -4169,8 +4169,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERIKA"), .items = {ITEM_HYPER_POTION, ITEM_FULL_HEAL}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_LeaderErika), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_LeaderErika), }, [TRAINER_LEADER_KOGA] = { .trainerClass = TRAINER_CLASS_LEADER, @@ -4179,8 +4179,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KOGA"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_FULL_HEAL}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_LeaderKoga), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_LeaderKoga), }, [TRAINER_LEADER_BLAINE] = { .trainerClass = TRAINER_CLASS_LEADER, @@ -4189,8 +4189,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BLAINE"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_FULL_HEAL}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_LeaderBlaine), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_LeaderBlaine), }, [TRAINER_LEADER_SABRINA] = { .trainerClass = TRAINER_CLASS_LEADER, @@ -4199,8 +4199,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SABRINA"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_FULL_HEAL}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_LeaderSabrina), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_LeaderSabrina), }, [TRAINER_GENTLEMAN_THOMAS] = { .trainerClass = TRAINER_CLASS_GENTLEMAN, @@ -4209,8 +4209,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("THOMAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GentlemanThomas), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GentlemanThomas), }, [TRAINER_GENTLEMAN_ARTHUR] = { .trainerClass = TRAINER_CLASS_GENTLEMAN, @@ -4219,8 +4219,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ARTHUR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GentlemanArthur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GentlemanArthur), }, [TRAINER_GENTLEMAN_TUCKER] = { .trainerClass = TRAINER_CLASS_GENTLEMAN, @@ -4229,8 +4229,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TUCKER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GentlemanTucker), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GentlemanTucker), }, [TRAINER_GENTLEMAN_NORTON] = { .trainerClass = TRAINER_CLASS_GENTLEMAN, @@ -4239,8 +4239,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GentlemanNorton), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GentlemanNorton), }, [TRAINER_GENTLEMAN_WALTER] = { .trainerClass = TRAINER_CLASS_GENTLEMAN, @@ -4249,8 +4249,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GentlemanWalter), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GentlemanWalter), }, [TRAINER_RIVAL_SS_ANNE_SQUIRTLE] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4259,8 +4259,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalSsAnneSquirtle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalSsAnneSquirtle), }, [TRAINER_RIVAL_SS_ANNE_BULBASAUR] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4269,8 +4269,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalSsAnneBulbasaur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalSsAnneBulbasaur), }, [TRAINER_RIVAL_SS_ANNE_CHARMANDER] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4279,8 +4279,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalSsAnneCharmander), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalSsAnneCharmander), }, [TRAINER_RIVAL_POKEMON_TOWER_SQUIRTLE] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4289,8 +4289,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalPokemonTowerSquirtle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalPokemonTowerSquirtle), }, [TRAINER_RIVAL_POKEMON_TOWER_BULBASAUR] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4299,8 +4299,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalPokemonTowerBulbasaur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalPokemonTowerBulbasaur), }, [TRAINER_RIVAL_POKEMON_TOWER_CHARMANDER] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4309,8 +4309,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalPokemonTowerCharmander), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalPokemonTowerCharmander), }, [TRAINER_RIVAL_SILPH_SQUIRTLE] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4319,8 +4319,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalSilphSquirtle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalSilphSquirtle), }, [TRAINER_RIVAL_SILPH_BULBASAUR] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4329,8 +4329,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalSilphBulbasaur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalSilphBulbasaur), }, [TRAINER_RIVAL_SILPH_CHARMANDER] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4339,8 +4339,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RivalSilphCharmander), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalSilphCharmander), }, [TRAINER_RIVAL_ROUTE22_LATE_SQUIRTLE] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4349,8 +4349,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RivalRoute22LateSquirtle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalRoute22LateSquirtle), }, [TRAINER_RIVAL_ROUTE22_LATE_BULBASAUR] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4359,8 +4359,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RivalRoute22LateBulbasaur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalRoute22LateBulbasaur), }, [TRAINER_RIVAL_ROUTE22_LATE_CHARMANDER] = { .trainerClass = TRAINER_CLASS_RIVAL_LATE, @@ -4369,8 +4369,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RivalRoute22LateCharmander), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_RivalRoute22LateCharmander), }, [TRAINER_CHAMPION_FIRST_SQUIRTLE] = { .trainerClass = TRAINER_CLASS_CHAMPION, @@ -4379,8 +4379,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_ChampionFirstSquirtle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_ChampionFirstSquirtle), }, [TRAINER_CHAMPION_FIRST_BULBASAUR] = { .trainerClass = TRAINER_CLASS_CHAMPION, @@ -4389,8 +4389,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_ChampionFirstBulbasaur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_ChampionFirstBulbasaur), }, [TRAINER_CHAMPION_FIRST_CHARMANDER] = { .trainerClass = TRAINER_CLASS_CHAMPION, @@ -4399,8 +4399,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_ChampionFirstCharmander), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_ChampionFirstCharmander), }, [TRAINER_CHANNELER_PATRICIA] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4409,8 +4409,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PATRICIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerPatricia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerPatricia), }, [TRAINER_CHANNELER_CARLY] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4419,8 +4419,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CARLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerCarly), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerCarly), }, [TRAINER_CHANNELER_HOPE] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4429,8 +4429,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HOPE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerHope), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerHope), }, [TRAINER_CHANNELER_PAULA] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4439,8 +4439,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAULA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerPaula), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerPaula), }, [TRAINER_CHANNELER_LAUREL] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4449,8 +4449,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAUREL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerLaurel), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerLaurel), }, [TRAINER_CHANNELER_JODY] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4459,8 +4459,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JODY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerJody), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerJody), }, [TRAINER_CHANNELER_TAMMY] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4469,8 +4469,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TAMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerTammy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerTammy), }, [TRAINER_CHANNELER_RUTH] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4479,8 +4479,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RUTH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerRuth), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerRuth), }, [TRAINER_CHANNELER_KARINA] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4489,8 +4489,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KARINA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerKarina), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerKarina), }, [TRAINER_CHANNELER_JANAE] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4499,8 +4499,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JANAE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerJanae), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerJanae), }, [TRAINER_CHANNELER_ANGELICA] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4509,8 +4509,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANGELICA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerAngelica), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerAngelica), }, [TRAINER_CHANNELER_EMILIA] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4519,8 +4519,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EMILIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerEmilia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerEmilia), }, [TRAINER_CHANNELER_JENNIFER] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4529,8 +4529,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNIFER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerJennifer), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerJennifer), }, [TRAINER_CHANNELER_1] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4539,8 +4539,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Channeler1), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Channeler1), }, [TRAINER_CHANNELER_2] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4549,8 +4549,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Channeler2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Channeler2), }, [TRAINER_CHANNELER_3] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4559,8 +4559,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Channeler3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Channeler3), }, [TRAINER_CHANNELER_4] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4569,8 +4569,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Channeler4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Channeler4), }, [TRAINER_CHANNELER_5] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4579,8 +4579,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Channeler5), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Channeler5), }, [TRAINER_CHANNELER_6] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4589,8 +4589,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Channeler6), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Channeler6), }, [TRAINER_CHANNELER_7] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4599,8 +4599,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Channeler7), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Channeler7), }, [TRAINER_CHANNELER_8] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4609,8 +4609,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Channeler8), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Channeler8), }, [TRAINER_CHANNELER_AMANDA] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4619,8 +4619,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMANDA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerAmanda), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerAmanda), }, [TRAINER_CHANNELER_STACY] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4629,8 +4629,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("STACY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerStacy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerStacy), }, [TRAINER_CHANNELER_TASHA] = { .trainerClass = TRAINER_CLASS_CHANNELER, @@ -4639,8 +4639,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TASHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_ChannelerTasha), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ChannelerTasha), }, [TRAINER_HIKER_JEREMY] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -4649,8 +4649,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEREMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerJeremy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerJeremy), }, [TRAINER_PICNICKER_ALMA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4659,8 +4659,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALMA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerAlma), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerAlma), }, [TRAINER_PICNICKER_SUSIE] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4669,8 +4669,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SUSIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerSusie), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerSusie), }, [TRAINER_PICNICKER_VALERIE] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4679,8 +4679,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("VALERIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerValerie), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerValerie), }, [TRAINER_PICNICKER_GWEN] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4689,8 +4689,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GWEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerGwen), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerGwen), }, [TRAINER_BIKER_VIRGIL] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -4699,8 +4699,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("VIRGIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerVirgil), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerVirgil), }, [TRAINER_CAMPER_FLINT] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -4709,8 +4709,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLINT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperFlint), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperFlint), }, [TRAINER_PICNICKER_MISSY] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4719,8 +4719,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MISSY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerMissy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerMissy), }, [TRAINER_PICNICKER_IRENE] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4729,8 +4729,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("IRENE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerIrene), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerIrene), }, [TRAINER_PICNICKER_DANA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4739,8 +4739,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerDana), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerDana), }, [TRAINER_PICNICKER_ARIANA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4749,8 +4749,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ARIANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerAriana), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerAriana), }, [TRAINER_PICNICKER_LEAH] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4759,8 +4759,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerLeah), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerLeah), }, [TRAINER_CAMPER_JUSTIN] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -4769,8 +4769,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUSTIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperJustin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperJustin), }, [TRAINER_PICNICKER_YAZMIN] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4779,8 +4779,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("YAZMIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerYazmin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerYazmin), }, [TRAINER_PICNICKER_KINDRA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4789,8 +4789,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KINDRA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerKindra), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerKindra), }, [TRAINER_PICNICKER_BECKY] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4799,8 +4799,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BECKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerBecky), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerBecky), }, [TRAINER_PICNICKER_CELIA] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -4809,8 +4809,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CELIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerCelia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerCelia), }, [TRAINER_GENTLEMAN_BROOKS] = { .trainerClass = TRAINER_CLASS_GENTLEMAN, @@ -4819,8 +4819,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GentlemanBrooks), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GentlemanBrooks), }, [TRAINER_GENTLEMAN_LAMAR] = { .trainerClass = TRAINER_CLASS_GENTLEMAN, @@ -4829,8 +4829,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAMAR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GentlemanLamar), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GentlemanLamar), }, [TRAINER_TWINS_ELI_ANNE] = { .trainerClass = TRAINER_CLASS_TWINS, @@ -4839,8 +4839,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELI & ANNE"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TwinsEliAnne), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TwinsEliAnne), }, [TRAINER_COOL_COUPLE_RAY_TYRA] = { .trainerClass = TRAINER_CLASS_COOL_COUPLE, @@ -4849,8 +4849,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RAY & TYRA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CoolCoupleRayTyra), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CoolCoupleRayTyra), }, [TRAINER_YOUNG_COUPLE_GIA_JES] = { .trainerClass = TRAINER_CLASS_YOUNG_COUPLE, @@ -4859,8 +4859,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GIA & JES"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungCoupleGiaJes), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungCoupleGiaJes), }, [TRAINER_TWINS_KIRI_JAN] = { .trainerClass = TRAINER_CLASS_TWINS, @@ -4869,8 +4869,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIRI & JAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TwinsKiriJan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TwinsKiriJan), }, [TRAINER_CRUSH_KIN_RON_MYA] = { .trainerClass = TRAINER_CLASS_CRUSH_KIN, @@ -4879,8 +4879,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RON & MYA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushKinRonMya), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushKinRonMya), }, [TRAINER_YOUNG_COUPLE_LEA_JED] = { .trainerClass = TRAINER_CLASS_YOUNG_COUPLE, @@ -4889,8 +4889,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEA & JED"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungCoupleLeaJed), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungCoupleLeaJed), }, [TRAINER_SIS_AND_BRO_LIA_LUC] = { .trainerClass = TRAINER_CLASS_SIS_AND_BRO, @@ -4899,8 +4899,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LIA & LUC"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SisAndBroLiaLuc), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SisAndBroLiaLuc), }, [TRAINER_SIS_AND_BRO_LIL_IAN] = { .trainerClass = TRAINER_CLASS_SIS_AND_BRO, @@ -4909,8 +4909,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LIL & IAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SisAndBroLilIan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SisAndBroLilIan), }, [TRAINER_BUG_CATCHER_3] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -4919,8 +4919,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcher3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcher3), }, [TRAINER_BUG_CATCHER_4] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -4929,8 +4929,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcher4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcher4), }, [TRAINER_BUG_CATCHER_5] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -4939,8 +4939,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcher5), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcher5), }, [TRAINER_BUG_CATCHER_6] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -4949,8 +4949,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcher6), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcher6), }, [TRAINER_BUG_CATCHER_7] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -4959,8 +4959,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcher7), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcher7), }, [TRAINER_BUG_CATCHER_8] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -4969,8 +4969,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcher8), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcher8), }, [TRAINER_YOUNGSTER_BEN_3] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -4979,8 +4979,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterBen3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterBen3), }, [TRAINER_YOUNGSTER_BEN_4] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -4989,8 +4989,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterBen4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterBen4), }, [TRAINER_YOUNGSTER_CHAD_2] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -4999,8 +4999,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHAD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterChad2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterChad2), }, [TRAINER_LASS_RELI_2] = { .trainerClass = TRAINER_CLASS_LASS, @@ -5009,8 +5009,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RELI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassReli2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassReli2), }, [TRAINER_LASS_RELI_3] = { .trainerClass = TRAINER_CLASS_LASS, @@ -5019,8 +5019,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RELI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassReli3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassReli3), }, [TRAINER_YOUNGSTER_TIMMY_2] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -5029,8 +5029,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterTimmy2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterTimmy2), }, [TRAINER_YOUNGSTER_TIMMY_3] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -5039,8 +5039,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterTimmy3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterTimmy3), }, [TRAINER_YOUNGSTER_TIMMY_4] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -5049,8 +5049,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterTimmy4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterTimmy4), }, [TRAINER_YOUNGSTER_CHAD_3] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -5059,8 +5059,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHAD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterChad3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterChad3), }, [TRAINER_LASS_JANICE_2] = { .trainerClass = TRAINER_CLASS_LASS, @@ -5069,8 +5069,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JANICE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassJanice2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassJanice2), }, [TRAINER_LASS_JANICE_3] = { .trainerClass = TRAINER_CLASS_LASS, @@ -5079,8 +5079,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JANICE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassJanice3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassJanice3), }, [TRAINER_YOUNGSTER_CHAD_4] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -5089,8 +5089,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHAD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterChad4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterChad4), }, [TRAINER_HIKER_FRANKLIN_2] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -5099,8 +5099,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("FRANKLIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerFranklin2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerFranklin2), }, [TRAINER_PKMN_PROF_PROF_OAK] = { .trainerClass = TRAINER_CLASS_PKMN_PROF, @@ -5109,8 +5109,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("PROF. OAK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PkmnProfProfOak), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PkmnProfProfOak), }, [TRAINER_PLAYER_BRENDAN] = { .trainerClass = TRAINER_CLASS_PLAYER, @@ -5119,8 +5119,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PlayerBrendan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PlayerBrendan), }, [TRAINER_PLAYER_MAY] = { .trainerClass = TRAINER_CLASS_PLAYER, @@ -5129,8 +5129,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PlayerMay), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PlayerMay), }, [TRAINER_PLAYER_RED] = { .trainerClass = TRAINER_CLASS_PLAYER, @@ -5139,8 +5139,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PlayerRed), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PlayerRed), }, [TRAINER_PLAYER_LEAF] = { .trainerClass = TRAINER_CLASS_PLAYER, @@ -5149,8 +5149,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEAF"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PlayerLeaf), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PlayerLeaf), }, [TRAINER_TEAM_ROCKET_GRUNT_42] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5159,8 +5159,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt42), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt42), }, [TRAINER_PSYCHIC_JACLYN] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -5169,8 +5169,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACLYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PsychicJaclyn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicJaclyn), }, [TRAINER_CRUSH_GIRL_SHARON] = { .trainerClass = TRAINER_CLASS_CRUSH_GIRL, @@ -5179,8 +5179,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHARON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushGirlSharon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushGirlSharon), }, [TRAINER_TUBER_AMIRA] = { .trainerClass = TRAINER_CLASS_TUBER, @@ -5189,8 +5189,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMIRA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TuberAmira), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TuberAmira), }, [TRAINER_PKMN_BREEDER_ALIZE] = { .trainerClass = TRAINER_CLASS_PKMN_BREEDER, @@ -5199,8 +5199,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALIZE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PkmnBreederAlize), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PkmnBreederAlize), }, [TRAINER_PKMN_RANGER_NICOLAS] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -5209,8 +5209,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICOLAS"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PkmnRangerNicolas), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerNicolas), }, [TRAINER_PKMN_RANGER_MADELINE] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -5219,8 +5219,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MADELINE"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PkmnRangerMadeline), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerMadeline), }, [TRAINER_AROMA_LADY_NIKKI] = { .trainerClass = TRAINER_CLASS_AROMA_LADY, @@ -5229,8 +5229,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NIKKI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_AromaLadyNikki), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_AromaLadyNikki), }, [TRAINER_RUIN_MANIAC_STANLY] = { .trainerClass = TRAINER_CLASS_RUIN_MANIAC, @@ -5239,8 +5239,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("STANLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RuinManiacStanly), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RuinManiacStanly), }, [TRAINER_LADY_JACKI] = { .trainerClass = TRAINER_CLASS_LADY, @@ -5249,8 +5249,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKI"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_LadyJacki), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LadyJacki), }, [TRAINER_PAINTER_DAISY] = { .trainerClass = TRAINER_CLASS_PAINTER, @@ -5259,8 +5259,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAISY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PainterDaisy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PainterDaisy), }, [TRAINER_BIKER_GOON] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -5269,8 +5269,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GOON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerGoon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerGoon), }, [TRAINER_BIKER_GOON_2] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -5279,8 +5279,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GOON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerGoon2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerGoon2), }, [TRAINER_BIKER_GOON_3] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -5289,8 +5289,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GOON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BikerGoon3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerGoon3), }, [TRAINER_BIKER_2] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -5299,8 +5299,8 @@ const struct Trainer gTrainers[] = { .trainerName = _(""), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_Biker2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_Biker2), }, [TRAINER_BUG_CATCHER_ANTHONY] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -5309,8 +5309,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANTHONY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherAnthony), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherAnthony), }, [TRAINER_BUG_CATCHER_CHARLIE] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -5319,8 +5319,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHARLIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherCharlie), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherCharlie), }, [TRAINER_TWINS_ELI_ANNE_2] = { .trainerClass = TRAINER_CLASS_TWINS, @@ -5329,8 +5329,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELI & ANNE"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TwinsEliAnne2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TwinsEliAnne2), }, [TRAINER_YOUNGSTER_JOHNSON] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -5339,8 +5339,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHNSON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterJohnson), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterJohnson), }, [TRAINER_BIKER_RICARDO] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -5349,8 +5349,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICARDO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_BikerRicardo), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerRicardo), }, [TRAINER_BIKER_JAREN] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -5359,8 +5359,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAREN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BikerJaren), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerJaren), }, [TRAINER_TEAM_ROCKET_GRUNT_43] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5369,8 +5369,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt43), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt43), }, [TRAINER_TEAM_ROCKET_GRUNT_44] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5379,8 +5379,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt44), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt44), }, [TRAINER_TEAM_ROCKET_GRUNT_45] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5389,8 +5389,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt45), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt45), }, [TRAINER_TEAM_ROCKET_GRUNT_46] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5399,8 +5399,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt46), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt46), }, [TRAINER_TEAM_ROCKET_GRUNT_47] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5409,8 +5409,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt47), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt47), }, [TRAINER_TEAM_ROCKET_GRUNT_48] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5419,8 +5419,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt48), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt48), }, [TRAINER_TEAM_ROCKET_ADMIN] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5429,8 +5429,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ADMIN"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_TeamRocketAdmin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_TeamRocketAdmin), }, [TRAINER_TEAM_ROCKET_ADMIN_2] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5439,8 +5439,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ADMIN"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_TeamRocketAdmin2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_TeamRocketAdmin2), }, [TRAINER_SCIENTIST_GIDEON] = { .trainerClass = TRAINER_CLASS_SCIENTIST, @@ -5449,8 +5449,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GIDEON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_ScientistGideon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_ScientistGideon), }, [TRAINER_SWIMMER_FEMALE_AMARA] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -5459,8 +5459,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMARA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleAmara), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleAmara), }, [TRAINER_SWIMMER_FEMALE_MARIA] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -5469,8 +5469,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleMaria), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleMaria), }, [TRAINER_SWIMMER_FEMALE_ABIGAIL] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -5479,8 +5479,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ABIGAIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleAbigail), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleAbigail), }, [TRAINER_SWIMMER_MALE_FINN] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -5489,8 +5489,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("FINN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleFinn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleFinn), }, [TRAINER_SWIMMER_MALE_GARRETT] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -5499,8 +5499,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GARRETT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleGarrett), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleGarrett), }, [TRAINER_FISHERMAN_TOMMY] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -5509,8 +5509,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TOMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanTommy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanTommy), }, [TRAINER_CRUSH_GIRL_TANYA] = { .trainerClass = TRAINER_CLASS_CRUSH_GIRL, @@ -5519,8 +5519,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TANYA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushGirlTanya), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushGirlTanya), }, [TRAINER_BLACK_BELT_SHEA] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -5529,8 +5529,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHEA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltShea), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltShea), }, [TRAINER_BLACK_BELT_HUGH] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -5539,8 +5539,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HUGH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltHugh), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltHugh), }, [TRAINER_CAMPER_BRYCE] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -5549,8 +5549,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRYCE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperBryce), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperBryce), }, [TRAINER_PICNICKER_CLAIRE] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -5559,8 +5559,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CLAIRE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerClaire), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerClaire), }, [TRAINER_CRUSH_KIN_MIK_KIA] = { .trainerClass = TRAINER_CLASS_CRUSH_KIN, @@ -5569,8 +5569,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIK & KIA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushKinMikKia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushKinMikKia), }, [TRAINER_AROMA_LADY_VIOLET] = { .trainerClass = TRAINER_CLASS_AROMA_LADY, @@ -5579,8 +5579,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("VIOLET"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_AromaLadyViolet), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_AromaLadyViolet), }, [TRAINER_TUBER_ALEXIS] = { .trainerClass = TRAINER_CLASS_TUBER, @@ -5589,8 +5589,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEXIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TuberAlexis), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TuberAlexis), }, [TRAINER_TWINS_JOY_MEG] = { .trainerClass = TRAINER_CLASS_TWINS, @@ -5599,8 +5599,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOY & MEG"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TwinsJoyMeg), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TwinsJoyMeg), }, [TRAINER_SWIMMER_FEMALE_TISHA] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -5609,8 +5609,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TISHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleTisha), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleTisha), }, [TRAINER_PAINTER_CELINA] = { .trainerClass = TRAINER_CLASS_PAINTER, @@ -5619,8 +5619,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CELINA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PainterCelina), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PainterCelina), }, [TRAINER_PAINTER_RAYNA] = { .trainerClass = TRAINER_CLASS_PAINTER, @@ -5629,8 +5629,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RAYNA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PainterRayna), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PainterRayna), }, [TRAINER_LADY_GILLIAN] = { .trainerClass = TRAINER_CLASS_LADY, @@ -5639,8 +5639,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GILLIAN"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_LadyGillian), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LadyGillian), }, [TRAINER_YOUNGSTER_DESTIN] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -5649,8 +5649,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DESTIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterDestin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterDestin), }, [TRAINER_SWIMMER_MALE_TOBY] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -5659,8 +5659,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TOBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleToby), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleToby), }, [TRAINER_TEAM_ROCKET_GRUNT_49] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5669,8 +5669,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt49), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt49), }, [TRAINER_TEAM_ROCKET_GRUNT_50] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5679,8 +5679,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_TeamRocketGrunt50), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt50), }, [TRAINER_TEAM_ROCKET_GRUNT_51] = { .trainerClass = TRAINER_CLASS_TEAM_ROCKET, @@ -5689,8 +5689,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TeamRocketGrunt51), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TeamRocketGrunt51), }, [TRAINER_BIRD_KEEPER_MILO] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -5699,8 +5699,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MILO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperMilo), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperMilo), }, [TRAINER_BIRD_KEEPER_CHAZ] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -5709,8 +5709,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHAZ"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperChaz), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperChaz), }, [TRAINER_BIRD_KEEPER_HAROLD] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -5719,8 +5719,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HAROLD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperHarold), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperHarold), }, [TRAINER_FISHERMAN_TYLOR] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -5729,8 +5729,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TYLOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanTylor), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanTylor), }, [TRAINER_SWIMMER_MALE_MYMO] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -5739,8 +5739,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MYMO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleMymo), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleMymo), }, [TRAINER_SWIMMER_FEMALE_NICOLE] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -5749,8 +5749,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICOLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleNicole), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleNicole), }, [TRAINER_SIS_AND_BRO_AVA_GEB] = { .trainerClass = TRAINER_CLASS_SIS_AND_BRO, @@ -5759,8 +5759,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AVA & GEB"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SisAndBroAvaGeb), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SisAndBroAvaGeb), }, [TRAINER_AROMA_LADY_ROSE] = { .trainerClass = TRAINER_CLASS_AROMA_LADY, @@ -5769,8 +5769,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROSE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_AromaLadyRose), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_AromaLadyRose), }, [TRAINER_SWIMMER_MALE_SAMIR] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -5779,8 +5779,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAMIR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleSamir), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleSamir), }, [TRAINER_SWIMMER_FEMALE_DENISE] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -5789,8 +5789,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DENISE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleDenise), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleDenise), }, [TRAINER_TWINS_MIU_MIA] = { .trainerClass = TRAINER_CLASS_TWINS, @@ -5799,8 +5799,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIU & MIA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TwinsMiuMia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TwinsMiuMia), }, [TRAINER_HIKER_EARL] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -5809,8 +5809,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EARL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerEarl), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerEarl), }, [TRAINER_RUIN_MANIAC_FOSTER] = { .trainerClass = TRAINER_CLASS_RUIN_MANIAC, @@ -5819,8 +5819,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("FOSTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RuinManiacFoster), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RuinManiacFoster), }, [TRAINER_RUIN_MANIAC_LARRY] = { .trainerClass = TRAINER_CLASS_RUIN_MANIAC, @@ -5829,8 +5829,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LARRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RuinManiacLarry), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RuinManiacLarry), }, [TRAINER_HIKER_DARYL] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -5839,8 +5839,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARYL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerDaryl), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerDaryl), }, [TRAINER_POKEMANIAC_HECTOR] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -5849,8 +5849,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HECTOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacHector), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacHector), }, [TRAINER_PSYCHIC_DARIO] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -5859,8 +5859,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARIO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PsychicDario), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicDario), }, [TRAINER_PSYCHIC_RODETTE] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -5869,8 +5869,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RODETTE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PsychicRodette), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicRodette), }, [TRAINER_AROMA_LADY_MIAH] = { .trainerClass = TRAINER_CLASS_AROMA_LADY, @@ -5879,8 +5879,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_AromaLadyMiah), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_AromaLadyMiah), }, [TRAINER_YOUNG_COUPLE_EVE_JON] = { .trainerClass = TRAINER_CLASS_YOUNG_COUPLE, @@ -5889,8 +5889,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EVE & JON"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungCoupleEveJon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungCoupleEveJon), }, [TRAINER_JUGGLER_MASON] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -5899,8 +5899,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MASON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_JugglerMason), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerMason), }, [TRAINER_CRUSH_GIRL_CYNDY] = { .trainerClass = TRAINER_CLASS_CRUSH_GIRL, @@ -5909,8 +5909,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CYNDY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushGirlCyndy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushGirlCyndy), }, [TRAINER_CRUSH_GIRL_JOCELYN] = { .trainerClass = TRAINER_CLASS_CRUSH_GIRL, @@ -5919,8 +5919,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOCELYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushGirlJocelyn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushGirlJocelyn), }, [TRAINER_TAMER_EVAN] = { .trainerClass = TRAINER_CLASS_TAMER, @@ -5929,8 +5929,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EVAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TamerEvan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TamerEvan), }, [TRAINER_POKEMANIAC_MARK_2] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -5939,8 +5939,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacMark2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacMark2), }, [TRAINER_PKMN_RANGER_LOGAN] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -5949,8 +5949,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LOGAN"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PkmnRangerLogan), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerLogan), }, [TRAINER_PKMN_RANGER_JACKSON] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -5959,8 +5959,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PkmnRangerJackson), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerJackson), }, [TRAINER_PKMN_RANGER_BETH] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -5969,8 +5969,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BETH"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PkmnRangerBeth), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerBeth), }, [TRAINER_PKMN_RANGER_KATELYN] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -5979,8 +5979,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYN"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PkmnRangerKatelyn), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerKatelyn), }, [TRAINER_COOLTRAINER_LEROY] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -5989,8 +5989,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEROY"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerLeroy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerLeroy), }, [TRAINER_COOLTRAINER_MICHELLE] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -5999,8 +5999,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MICHELLE"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerMichelle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerMichelle), }, [TRAINER_COOL_COUPLE_LEX_NYA] = { .trainerClass = TRAINER_CLASS_COOL_COUPLE, @@ -6009,8 +6009,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEX & NYA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CoolCoupleLexNya), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CoolCoupleLexNya), }, [TRAINER_RUIN_MANIAC_BRANDON] = { .trainerClass = TRAINER_CLASS_RUIN_MANIAC, @@ -6019,8 +6019,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRANDON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RuinManiacBrandon), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RuinManiacBrandon), }, [TRAINER_RUIN_MANIAC_BENJAMIN] = { .trainerClass = TRAINER_CLASS_RUIN_MANIAC, @@ -6029,8 +6029,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENJAMIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_RuinManiacBenjamin), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RuinManiacBenjamin), }, [TRAINER_PAINTER_EDNA] = { .trainerClass = TRAINER_CLASS_PAINTER, @@ -6039,8 +6039,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDNA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PainterEdna), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PainterEdna), }, [TRAINER_GENTLEMAN_CLIFFORD] = { .trainerClass = TRAINER_CLASS_GENTLEMAN, @@ -6049,8 +6049,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CLIFFORD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GentlemanClifford), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GentlemanClifford), }, [TRAINER_LADY_SELPHY] = { .trainerClass = TRAINER_CLASS_LADY, @@ -6059,8 +6059,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SELPHY"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_CUSTOM_MOVES(sParty_LadySelphy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LadySelphy), }, [TRAINER_RUIN_MANIAC_LAWSON] = { .trainerClass = TRAINER_CLASS_RUIN_MANIAC, @@ -6069,8 +6069,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAWSON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RuinManiacLawson), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RuinManiacLawson), }, [TRAINER_PSYCHIC_LAURA] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -6079,8 +6079,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAURA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PsychicLaura), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicLaura), }, [TRAINER_PKMN_BREEDER_BETHANY] = { .trainerClass = TRAINER_CLASS_PKMN_BREEDER, @@ -6089,8 +6089,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BETHANY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PkmnBreederBethany), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PkmnBreederBethany), }, [TRAINER_PKMN_BREEDER_ALLISON] = { .trainerClass = TRAINER_CLASS_PKMN_BREEDER, @@ -6099,8 +6099,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALLISON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PkmnBreederAllison), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PkmnBreederAllison), }, [TRAINER_BUG_CATCHER_GARRET] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -6109,8 +6109,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GARRET"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherGarret), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherGarret), }, [TRAINER_BUG_CATCHER_JONAH] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -6119,8 +6119,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JONAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherJonah), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherJonah), }, [TRAINER_BUG_CATCHER_VANCE] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -6129,8 +6129,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("VANCE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherVance), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherVance), }, [TRAINER_YOUNGSTER_NASH] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -6139,8 +6139,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NASH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterNash), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterNash), }, [TRAINER_YOUNGSTER_CORDELL] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -6149,8 +6149,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CORDELL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterCordell), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterCordell), }, [TRAINER_LASS_DALIA] = { .trainerClass = TRAINER_CLASS_LASS, @@ -6159,8 +6159,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DALIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassDalia), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassDalia), }, [TRAINER_LASS_JOANA] = { .trainerClass = TRAINER_CLASS_LASS, @@ -6169,8 +6169,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassJoana), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassJoana), }, [TRAINER_CAMPER_RILEY] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6179,8 +6179,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RILEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperRiley), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperRiley), }, [TRAINER_PICNICKER_MARCY] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6189,8 +6189,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARCY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerMarcy), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerMarcy), }, [TRAINER_RUIN_MANIAC_LAYTON] = { .trainerClass = TRAINER_CLASS_RUIN_MANIAC, @@ -6199,8 +6199,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAYTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RuinManiacLayton), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RuinManiacLayton), }, [TRAINER_PICNICKER_KELSEY_2] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6209,8 +6209,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KELSEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerKelsey2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerKelsey2), }, [TRAINER_PICNICKER_KELSEY_3] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6219,8 +6219,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KELSEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerKelsey3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerKelsey3), }, [TRAINER_PICNICKER_KELSEY_4] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6229,8 +6229,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KELSEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerKelsey4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerKelsey4), }, [TRAINER_CAMPER_RICKY_2] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6239,8 +6239,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperRicky2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperRicky2), }, [TRAINER_CAMPER_RICKY_3] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6249,8 +6249,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperRicky3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperRicky3), }, [TRAINER_CAMPER_RICKY_4] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6259,8 +6259,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperRicky4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperRicky4), }, [TRAINER_CAMPER_JEFF_2] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6269,8 +6269,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFF"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperJeff2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperJeff2), }, [TRAINER_CAMPER_JEFF_3] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6279,8 +6279,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFF"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperJeff3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperJeff3), }, [TRAINER_CAMPER_JEFF_4] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6289,8 +6289,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFF"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperJeff4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperJeff4), }, [TRAINER_PICNICKER_ISABELLE_2] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6299,8 +6299,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerIsabelle2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerIsabelle2), }, [TRAINER_PICNICKER_ISABELLE_3] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6309,8 +6309,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerIsabelle3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerIsabelle3), }, [TRAINER_PICNICKER_ISABELLE_4] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6319,8 +6319,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerIsabelle4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerIsabelle4), }, [TRAINER_YOUNGSTER_YASU_2] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -6329,8 +6329,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("YASU"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterYasu2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterYasu2), }, [TRAINER_YOUNGSTER_YASU_3] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -6339,8 +6339,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("YASU"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterYasu3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterYasu3), }, [TRAINER_ENGINEER_BERNIE_2] = { .trainerClass = TRAINER_CLASS_ENGINEER, @@ -6349,8 +6349,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_EngineerBernie2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_EngineerBernie2), }, [TRAINER_GAMER_DARIAN_2] = { .trainerClass = TRAINER_CLASS_GAMER, @@ -6359,8 +6359,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARIAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GamerDarian2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GamerDarian2), }, [TRAINER_CAMPER_CHRIS_2] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6369,8 +6369,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHRIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperChris2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperChris2), }, [TRAINER_CAMPER_CHRIS_3] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6379,8 +6379,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHRIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperChris3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperChris3), }, [TRAINER_CAMPER_CHRIS_4] = { .trainerClass = TRAINER_CLASS_CAMPER, @@ -6389,8 +6389,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHRIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CamperChris4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CamperChris4), }, [TRAINER_PICNICKER_ALICIA_2] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6399,8 +6399,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALICIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerAlicia2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerAlicia2), }, [TRAINER_PICNICKER_ALICIA_3] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6409,8 +6409,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALICIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerAlicia3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerAlicia3), }, [TRAINER_PICNICKER_ALICIA_4] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6419,8 +6419,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALICIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerAlicia4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerAlicia4), }, [TRAINER_HIKER_JEREMY_2] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -6429,8 +6429,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEREMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerJeremy2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerJeremy2), }, [TRAINER_POKEMANIAC_MARK_3] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -6439,8 +6439,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacMark3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacMark3), }, [TRAINER_POKEMANIAC_HERMAN_2] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -6449,8 +6449,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HERMAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacHerman2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacHerman2), }, [TRAINER_POKEMANIAC_HERMAN_3] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -6459,8 +6459,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HERMAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacHerman3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacHerman3), }, [TRAINER_HIKER_TRENT_2] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -6469,8 +6469,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TRENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerTrent2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerTrent2), }, [TRAINER_LASS_MEGAN_2] = { .trainerClass = TRAINER_CLASS_LASS, @@ -6479,8 +6479,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MEGAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassMegan2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassMegan2), }, [TRAINER_LASS_MEGAN_3] = { .trainerClass = TRAINER_CLASS_LASS, @@ -6489,8 +6489,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MEGAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_LassMegan3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_LassMegan3), }, [TRAINER_SUPER_NERD_GLENN_2] = { .trainerClass = TRAINER_CLASS_SUPER_NERD, @@ -6499,8 +6499,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GLENN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SuperNerdGlenn2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SuperNerdGlenn2), }, [TRAINER_GAMER_RICH_2] = { .trainerClass = TRAINER_CLASS_GAMER, @@ -6509,8 +6509,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_GamerRich2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_GamerRich2), }, [TRAINER_BIKER_JAREN_2] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -6519,8 +6519,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAREN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BikerJaren2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerJaren2), }, [TRAINER_FISHERMAN_ELLIOT_2] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -6529,8 +6529,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELLIOT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanElliot2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanElliot2), }, [TRAINER_ROCKER_LUCA_2] = { .trainerClass = TRAINER_CLASS_ROCKER, @@ -6539,8 +6539,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUCA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RockerLuca2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RockerLuca2), }, [TRAINER_BEAUTY_SHEILA_2] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -6549,8 +6549,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHEILA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautySheila2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautySheila2), }, [TRAINER_BIRD_KEEPER_ROBERT_2] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6559,8 +6559,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBERT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperRobert2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperRobert2), }, [TRAINER_BIRD_KEEPER_ROBERT_3] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6569,8 +6569,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBERT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperRobert3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperRobert3), }, [TRAINER_PICNICKER_SUSIE_2] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6579,8 +6579,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SUSIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerSusie2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerSusie2), }, [TRAINER_PICNICKER_SUSIE_3] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6589,8 +6589,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SUSIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerSusie3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerSusie3), }, [TRAINER_PICNICKER_SUSIE_4] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6599,8 +6599,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SUSIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerSusie4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerSusie4), }, [TRAINER_BIKER_LUKAS_2] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -6609,8 +6609,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUKAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BikerLukas2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerLukas2), }, [TRAINER_BIRD_KEEPER_BENNY_2] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6619,8 +6619,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperBenny2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperBenny2), }, [TRAINER_BIRD_KEEPER_BENNY_3] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6629,8 +6629,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperBenny3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperBenny3), }, [TRAINER_BIRD_KEEPER_MARLON_2] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6639,8 +6639,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARLON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperMarlon2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperMarlon2), }, [TRAINER_BIRD_KEEPER_MARLON_3] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6649,8 +6649,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARLON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperMarlon3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperMarlon3), }, [TRAINER_BEAUTY_GRACE_2] = { .trainerClass = TRAINER_CLASS_BEAUTY, @@ -6659,8 +6659,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRACE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BeautyGrace2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BeautyGrace2), }, [TRAINER_BIRD_KEEPER_CHESTER_2] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6669,8 +6669,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHESTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperChester2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperChester2), }, [TRAINER_BIRD_KEEPER_CHESTER_3] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6679,8 +6679,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHESTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperChester3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperChester3), }, [TRAINER_PICNICKER_BECKY_2] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6689,8 +6689,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BECKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerBecky2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerBecky2), }, [TRAINER_PICNICKER_BECKY_3] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6699,8 +6699,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BECKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerBecky3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerBecky3), }, [TRAINER_PICNICKER_BECKY_4] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6709,8 +6709,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BECKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerBecky4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerBecky4), }, [TRAINER_CRUSH_KIN_RON_MYA_2] = { .trainerClass = TRAINER_CLASS_CRUSH_KIN, @@ -6719,8 +6719,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RON & MYA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushKinRonMya2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushKinRonMya2), }, [TRAINER_CRUSH_KIN_RON_MYA_3] = { .trainerClass = TRAINER_CLASS_CRUSH_KIN, @@ -6729,8 +6729,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RON & MYA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushKinRonMya3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushKinRonMya3), }, [TRAINER_CRUSH_KIN_RON_MYA_4] = { .trainerClass = TRAINER_CLASS_CRUSH_KIN, @@ -6739,8 +6739,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RON & MYA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushKinRonMya4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushKinRonMya4), }, [TRAINER_BIKER_RUBEN_2] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -6749,8 +6749,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RUBEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BikerRuben2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerRuben2), }, [TRAINER_CUE_BALL_CAMRON_2] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -6759,8 +6759,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMRON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallCamron2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallCamron2), }, [TRAINER_BIKER_JAXON_2] = { .trainerClass = TRAINER_CLASS_BIKER, @@ -6769,8 +6769,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAXON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BikerJaxon2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BikerJaxon2), }, [TRAINER_CUE_BALL_ISAIAH_2] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -6779,8 +6779,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAIAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallIsaiah2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallIsaiah2), }, [TRAINER_CUE_BALL_COREY_2] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -6789,8 +6789,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COREY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallCorey2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallCorey2), }, [TRAINER_BIRD_KEEPER_JACOB_2] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6799,8 +6799,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperJacob2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperJacob2), }, [TRAINER_BIRD_KEEPER_JACOB_3] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -6809,8 +6809,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperJacob3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperJacob3), }, [TRAINER_SWIMMER_FEMALE_ALICE_2] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -6819,8 +6819,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALICE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleAlice2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleAlice2), }, [TRAINER_SWIMMER_MALE_DARRIN_2] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -6829,8 +6829,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARRIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleDarrin2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleDarrin2), }, [TRAINER_PICNICKER_MISSY_2] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6839,8 +6839,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MISSY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerMissy2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerMissy2), }, [TRAINER_PICNICKER_MISSY_3] = { .trainerClass = TRAINER_CLASS_PICNICKER, @@ -6849,8 +6849,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MISSY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PicnickerMissy3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PicnickerMissy3), }, [TRAINER_FISHERMAN_WADE_2] = { .trainerClass = TRAINER_CLASS_FISHERMAN, @@ -6859,8 +6859,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("WADE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_FishermanWade2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_FishermanWade2), }, [TRAINER_SWIMMER_MALE_JACK_2] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -6869,8 +6869,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleJack2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleJack2), }, [TRAINER_SIS_AND_BRO_LIL_IAN_2] = { .trainerClass = TRAINER_CLASS_SIS_AND_BRO, @@ -6879,8 +6879,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LIL & IAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SisAndBroLilIan2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SisAndBroLilIan2), }, [TRAINER_SIS_AND_BRO_LIL_IAN_3] = { .trainerClass = TRAINER_CLASS_SIS_AND_BRO, @@ -6889,8 +6889,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LIL & IAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SisAndBroLilIan3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SisAndBroLilIan3), }, [TRAINER_SWIMMER_MALE_FINN_2] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -6899,8 +6899,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("FINN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleFinn2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleFinn2), }, [TRAINER_CRUSH_GIRL_SHARON_2] = { .trainerClass = TRAINER_CLASS_CRUSH_GIRL, @@ -6909,8 +6909,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHARON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushGirlSharon2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushGirlSharon2), }, [TRAINER_CRUSH_GIRL_SHARON_3] = { .trainerClass = TRAINER_CLASS_CRUSH_GIRL, @@ -6919,8 +6919,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHARON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushGirlSharon3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushGirlSharon3), }, [TRAINER_CRUSH_GIRL_TANYA_2] = { .trainerClass = TRAINER_CLASS_CRUSH_GIRL, @@ -6929,8 +6929,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TANYA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushGirlTanya2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushGirlTanya2), }, [TRAINER_CRUSH_GIRL_TANYA_3] = { .trainerClass = TRAINER_CLASS_CRUSH_GIRL, @@ -6939,8 +6939,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TANYA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushGirlTanya3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushGirlTanya3), }, [TRAINER_BLACK_BELT_SHEA_2] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -6949,8 +6949,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHEA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltShea2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltShea2), }, [TRAINER_BLACK_BELT_SHEA_3] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -6959,8 +6959,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHEA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltShea3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltShea3), }, [TRAINER_BLACK_BELT_HUGH_2] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -6969,8 +6969,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HUGH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltHugh2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltHugh2), }, [TRAINER_BLACK_BELT_HUGH_3] = { .trainerClass = TRAINER_CLASS_BLACK_BELT, @@ -6979,8 +6979,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HUGH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_BlackBeltHugh3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BlackBeltHugh3), }, [TRAINER_CRUSH_KIN_MIK_KIA_2] = { .trainerClass = TRAINER_CLASS_CRUSH_KIN, @@ -6989,8 +6989,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIK & KIA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushKinMikKia2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushKinMikKia2), }, [TRAINER_CRUSH_KIN_MIK_KIA_3] = { .trainerClass = TRAINER_CLASS_CRUSH_KIN, @@ -6999,8 +6999,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIK & KIA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushKinMikKia3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushKinMikKia3), }, [TRAINER_TUBER_AMIRA_2] = { .trainerClass = TRAINER_CLASS_TUBER, @@ -7009,8 +7009,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMIRA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TuberAmira2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TuberAmira2), }, [TRAINER_TWINS_JOY_MEG_2] = { .trainerClass = TRAINER_CLASS_TWINS, @@ -7019,8 +7019,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOY & MEG"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TwinsJoyMeg2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TwinsJoyMeg2), }, [TRAINER_PAINTER_RAYNA_2] = { .trainerClass = TRAINER_CLASS_PAINTER, @@ -7029,8 +7029,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RAYNA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PainterRayna2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PainterRayna2), }, [TRAINER_YOUNGSTER_DESTIN_2] = { .trainerClass = TRAINER_CLASS_YOUNGSTER, @@ -7039,8 +7039,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DESTIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungsterDestin2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungsterDestin2), }, [TRAINER_PKMN_BREEDER_ALIZE_2] = { .trainerClass = TRAINER_CLASS_PKMN_BREEDER, @@ -7049,8 +7049,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALIZE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PkmnBreederAlize2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PkmnBreederAlize2), }, [TRAINER_YOUNG_COUPLE_GIA_JES_2] = { .trainerClass = TRAINER_CLASS_YOUNG_COUPLE, @@ -7059,8 +7059,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GIA & JES"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungCoupleGiaJes2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungCoupleGiaJes2), }, [TRAINER_YOUNG_COUPLE_GIA_JES_3] = { .trainerClass = TRAINER_CLASS_YOUNG_COUPLE, @@ -7069,8 +7069,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("GIA & JES"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_YoungCoupleGiaJes3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_YoungCoupleGiaJes3), }, [TRAINER_BIRD_KEEPER_MILO_2] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -7079,8 +7079,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MILO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperMilo2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperMilo2), }, [TRAINER_BIRD_KEEPER_CHAZ_2] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -7089,8 +7089,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHAZ"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperChaz2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperChaz2), }, [TRAINER_BIRD_KEEPER_HAROLD_2] = { .trainerClass = TRAINER_CLASS_BIRD_KEEPER, @@ -7099,8 +7099,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HAROLD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BirdKeeperHarold2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BirdKeeperHarold2), }, [TRAINER_SWIMMER_FEMALE_NICOLE_2] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -7109,8 +7109,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICOLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleNicole2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleNicole2), }, [TRAINER_PSYCHIC_JACLYN_2] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -7119,8 +7119,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACLYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PsychicJaclyn2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicJaclyn2), }, [TRAINER_SWIMMER_MALE_SAMIR_2] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -7129,8 +7129,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAMIR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleSamir2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleSamir2), }, [TRAINER_HIKER_EARL_2] = { .trainerClass = TRAINER_CLASS_HIKER, @@ -7139,8 +7139,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EARL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_HikerEarl2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_HikerEarl2), }, [TRAINER_RUIN_MANIAC_LARRY_2] = { .trainerClass = TRAINER_CLASS_RUIN_MANIAC, @@ -7149,8 +7149,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LARRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_RuinManiacLarry2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_RuinManiacLarry2), }, [TRAINER_POKEMANIAC_HECTOR_2] = { .trainerClass = TRAINER_CLASS_POKEMANIAC, @@ -7159,8 +7159,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("HECTOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_PokemaniacHector2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PokemaniacHector2), }, [TRAINER_PSYCHIC_DARIO_2] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -7169,8 +7169,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARIO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PsychicDario2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicDario2), }, [TRAINER_PSYCHIC_RODETTE_2] = { .trainerClass = TRAINER_CLASS_PSYCHIC, @@ -7179,8 +7179,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("RODETTE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PsychicRodette2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_PsychicRodette2), }, [TRAINER_JUGGLER_MASON_2] = { .trainerClass = TRAINER_CLASS_JUGGLER, @@ -7189,8 +7189,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MASON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_JugglerMason2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_JugglerMason2), }, [TRAINER_PKMN_RANGER_NICOLAS_2] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -7199,8 +7199,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICOLAS"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PkmnRangerNicolas2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerNicolas2), }, [TRAINER_PKMN_RANGER_MADELINE_2] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -7209,8 +7209,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MADELINE"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PkmnRangerMadeline2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerMadeline2), }, [TRAINER_CRUSH_GIRL_CYNDY_2] = { .trainerClass = TRAINER_CLASS_CRUSH_GIRL, @@ -7219,8 +7219,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("CYNDY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = ITEM_DEFAULT_MOVES(sParty_CrushGirlCyndy2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CrushGirlCyndy2), }, [TRAINER_TAMER_EVAN_2] = { .trainerClass = TRAINER_CLASS_TAMER, @@ -7229,8 +7229,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("EVAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TamerEvan2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TamerEvan2), }, [TRAINER_PKMN_RANGER_JACKSON_2] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -7239,8 +7239,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PkmnRangerJackson2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerJackson2), }, [TRAINER_PKMN_RANGER_KATELYN_2] = { .trainerClass = TRAINER_CLASS_PKMN_RANGER, @@ -7249,8 +7249,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYN"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_PkmnRangerKatelyn2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_PkmnRangerKatelyn2), }, [TRAINER_COOLTRAINER_LEROY_2] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -7259,8 +7259,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEROY"), .items = {ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerLeroy2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerLeroy2), }, [TRAINER_COOLTRAINER_MICHELLE_2] = { .trainerClass = TRAINER_CLASS_COOLTRAINER, @@ -7269,8 +7269,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MICHELLE"), .items = {ITEM_HYPER_POTION}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CooltrainerMichelle2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CooltrainerMichelle2), }, [TRAINER_COOL_COUPLE_LEX_NYA_2] = { .trainerClass = TRAINER_CLASS_COOL_COUPLE, @@ -7279,8 +7279,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEX & NYA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = NO_ITEM_CUSTOM_MOVES(sParty_CoolCoupleLexNya2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_CoolCoupleLexNya2), }, [TRAINER_BUG_CATCHER_COLTON_2] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -7289,8 +7289,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COLTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherColton2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherColton2), }, [TRAINER_BUG_CATCHER_COLTON_3] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -7299,8 +7299,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COLTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherColton3), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherColton3), }, [TRAINER_BUG_CATCHER_COLTON_4] = { .trainerClass = TRAINER_CLASS_BUG_CATCHER, @@ -7309,8 +7309,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("COLTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_BugCatcherColton4), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_BugCatcherColton4), }, [TRAINER_SWIMMER_MALE_MATTHEW_2] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -7319,8 +7319,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MATTHEW"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleMatthew2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleMatthew2), }, [TRAINER_SWIMMER_MALE_TONY_2] = { .trainerClass = TRAINER_CLASS_SWIMMER_M, @@ -7329,8 +7329,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TONY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerMaleTony2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerMaleTony2), }, [TRAINER_SWIMMER_FEMALE_MELISSA_2] = { .trainerClass = TRAINER_CLASS_SWIMMER_F, @@ -7339,8 +7339,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("MELISSA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_SwimmerFemaleMelissa2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_SwimmerFemaleMelissa2), }, [TRAINER_ELITE_FOUR_LORELEI_2] = { .trainerClass = TRAINER_CLASS_ELITE_FOUR, @@ -7349,8 +7349,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LORELEI"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_EliteFourLorelei2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_EliteFourLorelei2), }, [TRAINER_ELITE_FOUR_BRUNO_2] = { .trainerClass = TRAINER_CLASS_ELITE_FOUR, @@ -7359,8 +7359,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRUNO"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_EliteFourBruno2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_EliteFourBruno2), }, [TRAINER_ELITE_FOUR_AGATHA_2] = { .trainerClass = TRAINER_CLASS_ELITE_FOUR, @@ -7369,8 +7369,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("AGATHA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_EliteFourAgatha2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_EliteFourAgatha2), }, [TRAINER_ELITE_FOUR_LANCE_2] = { .trainerClass = TRAINER_CLASS_ELITE_FOUR, @@ -7379,8 +7379,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("LANCE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_EliteFourLance2), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_EliteFourLance2), }, [TRAINER_CHAMPION_REMATCH_SQUIRTLE] = { .trainerClass = TRAINER_CLASS_CHAMPION, @@ -7389,8 +7389,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_ChampionRematchSquirtle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_ChampionRematchSquirtle), }, [TRAINER_CHAMPION_REMATCH_BULBASAUR] = { .trainerClass = TRAINER_CLASS_CHAMPION, @@ -7399,8 +7399,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_ChampionRematchBulbasaur), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_ChampionRematchBulbasaur), }, [TRAINER_CHAMPION_REMATCH_CHARMANDER] = { .trainerClass = TRAINER_CLASS_CHAMPION, @@ -7409,8 +7409,8 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, - .party = ITEM_CUSTOM_MOVES(sParty_ChampionRematchCharmander), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .party = TRAINER_PARTY(sParty_ChampionRematchCharmander), }, [TRAINER_CUE_BALL_PAXTON] = { .trainerClass = TRAINER_CLASS_CUE_BALL, @@ -7419,17 +7419,17 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAXTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_CueBallPaxton), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_CueBallPaxton), }, [TRAINER_TEST_BATTLE] = { - .trainerClass = TRAINER_CLASS_LASS, - .encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_FEMALE | F_TRAINER_FEMALE, - .trainerPic = TRAINER_PIC_LASS, + .trainerClass = TRAINER_CLASS_BUG_CATCHER, + .encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE, + .trainerPic = TRAINER_PIC_BUG_CATCHER, .trainerName = _("TESTBATTLE"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, - .party = NO_ITEM_DEFAULT_MOVES(sParty_TestBattle), + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, + .party = TRAINER_PARTY(sParty_TestBattle), }, }; diff --git a/src/pokemon.c b/src/pokemon.c index 0a9a86db2..20d386311 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -62,7 +62,6 @@ static EWRAM_DATA struct MonSpritesGfxManager *sMonSpritesGfxManager = NULL; static union PokemonSubstruct *GetSubstruct(struct BoxPokemon *boxMon, u32 personality, u8 substructType); static bool8 IsShinyOtIdPersonality(u32 otId, u32 personality); -static u8 GetNatureFromPersonality(u32 personality); static bool8 PartyMonHasStatus(struct Pokemon *mon, u32 unused, u32 healMask, u8 battleId); static bool8 IsPokemonStorageFull(void); static u8 CopyMonToPC(struct Pokemon *mon); @@ -3982,7 +3981,7 @@ u8 GetNature(struct Pokemon *mon) return GetMonData(mon, MON_DATA_PERSONALITY, NULL) % NUM_NATURES; } -static u8 GetNatureFromPersonality(u32 personality) +u8 GetNatureFromPersonality(u32 personality) { return personality % NUM_NATURES; } @@ -5590,9 +5589,9 @@ u16 FacilityClassToPicIndex(u16 facilityClass) u16 PlayerGenderToFrontTrainerPicId(u8 playerGender) { if (playerGender != MALE) - return FacilityClassToPicIndex(FACILITY_CLASS_MAY); + return FacilityClassToPicIndex(FACILITY_CLASS_LEAF); else - return FacilityClassToPicIndex(FACILITY_CLASS_BRENDAN); + return FacilityClassToPicIndex(FACILITY_CLASS_RED); } void HandleSetPokedexFlag(u16 nationalNum, u8 caseId, u32 personality) diff --git a/src/union_room.c b/src/union_room.c index a33af4f3a..4748f037d 100644 --- a/src/union_room.c +++ b/src/union_room.c @@ -4280,7 +4280,7 @@ static void ViewURoomPartnerTrainerCard(u8 *unused, struct WirelessLink_URoom * DynamicPlaceholderTextUtil_Reset(); - StringCopy(uroom->trainerCardStrBuffer[0], gTrainerClassNames[GetUnionRoomTrainerClass()]); + StringCopy(uroom->trainerCardStrBuffer[0], gTrainerClasses[GetUnionRoomTrainerClass()].name); DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, uroom->trainerCardStrBuffer[0]); DynamicPlaceholderTextUtil_SetPlaceholderPtr(1, trainerCard->rse.playerName); From 638a089e06da89a2b2ca28b1b0c714fe40a38bf6 Mon Sep 17 00:00:00 2001 From: cawtds Date: Sat, 11 May 2024 02:36:12 +0200 Subject: [PATCH 02/11] updated AI --- data/battle_ai_scripts.s | 3262 ----------------- include/battle.h | 86 +- include/battle_ai_main.h | 96 + include/battle_ai_script_commands.h | 22 - include/battle_ai_switch_items.h | 24 +- include/battle_ai_util.h | 196 + include/battle_script_commands.h | 5 + include/battle_util.h | 29 +- include/constants/battle.h | 1 + include/constants/battle_ai.h | 65 +- include/constants/global.h | 1 + include/pokemon.h | 4 +- ld_script.ld | 8 +- src/battle_ai_main.c | 5192 +++++++++++++++++++++++++++ src/battle_ai_script_commands.c | 2068 ----------- src/battle_ai_switch_items.c | 2233 ++++++++++-- src/battle_ai_util.c | 3724 +++++++++++++++++++ src/battle_controller_opponent.c | 176 +- src/battle_controllers.c | 6 +- src/battle_main.c | 3 +- src/battle_message.c | 18 +- src/battle_script_commands.c | 11 +- src/battle_util.c | 369 +- src/data/trainer_parties.h | 1 + src/party_menu.c | 18 + src/pokemon.c | 160 +- sym_ewram.txt | 2 +- 27 files changed, 11759 insertions(+), 6021 deletions(-) delete mode 100644 data/battle_ai_scripts.s create mode 100644 include/battle_ai_main.h delete mode 100644 include/battle_ai_script_commands.h create mode 100644 include/battle_ai_util.h create mode 100644 src/battle_ai_main.c delete mode 100644 src/battle_ai_script_commands.c create mode 100644 src/battle_ai_util.c diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s deleted file mode 100644 index 13118d00c..000000000 --- a/data/battle_ai_scripts.s +++ /dev/null @@ -1,3262 +0,0 @@ -#include "constants/battle.h" -#include "constants/battle_ai.h" -#include "constants/abilities.h" -#include "constants/items.h" -#include "constants/moves.h" -#include "constants/battle_move_effects.h" -#include "constants/hold_effects.h" -#include "constants/pokemon.h" - .include "asm/macros/battle_ai_script.inc" - - .section script_data, "aw", %progbits - -@ The FRLG scripts are improved subtly by Emerald in a few places -@ To make adding these improvements easier they are commented and tagged with "Improvement in Emerald" -@ Emerald also adds a few entirely new AI commands (mostly to expand Double Battle AI), which are not included - - .align 2 -gBattleAI_ScriptsTable:: - .4byte AI_CheckBadMove - .4byte AI_CheckViability - .4byte AI_TryToFaint - .4byte AI_SetupFirstTurn - .4byte AI_Risky - .4byte AI_PreferStrongestMove - .4byte AI_PreferBatonPass - .4byte AI_DoubleBattle - .4byte AI_HPAware - .4byte AI_Unknown - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Roaming - .4byte AI_Safari - .4byte AI_FirstBattle - -AI_CheckBadMove:: -@ if_move MOVE_FISSURE, AI_CBM_CheckIfNegatesType @ Improvement in Emerald -@ if_move MOVE_HORN_DRILL, AI_CBM_CheckIfNegatesType - get_how_powerful_move_is - if_equal MOVE_POWER_DISCOURAGED, AI_CheckBadMove_CheckSoundproof - -AI_CBM_CheckIfNegatesType:: - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_VOLT_ABSORB, CheckIfVoltAbsorbCancelsElectric - if_equal ABILITY_WATER_ABSORB, CheckIfWaterAbsorbCancelsWater - if_equal ABILITY_FLASH_FIRE, CheckIfFlashFireCancelsFire - if_equal ABILITY_WONDER_GUARD, CheckIfWonderGuardCancelsMove - if_equal ABILITY_LEVITATE, CheckIfLevitateCancelsGroundMove - goto AI_CheckBadMove_CheckSoundproof - -CheckIfVoltAbsorbCancelsElectric:: - get_curr_move_type - if_equal_ TYPE_ELECTRIC, Score_Minus12 - goto AI_CheckBadMove_CheckSoundproof - -CheckIfWaterAbsorbCancelsWater:: - get_curr_move_type - if_equal_ TYPE_WATER, Score_Minus12 - goto AI_CheckBadMove_CheckSoundproof - -CheckIfFlashFireCancelsFire:: - get_curr_move_type - if_equal_ TYPE_FIRE, Score_Minus12 - goto AI_CheckBadMove_CheckSoundproof - -CheckIfWonderGuardCancelsMove:: - if_type_effectiveness AI_EFFECTIVENESS_x2, AI_CheckBadMove_CheckSoundproof - goto Score_Minus10 - -CheckIfLevitateCancelsGroundMove:: - get_curr_move_type - if_equal_ TYPE_GROUND, Score_Minus10 - -AI_CheckBadMove_CheckSoundproof:: - get_ability AI_TARGET - if_not_equal ABILITY_SOUNDPROOF, AI_CheckBadMove_CheckEffect - if_move MOVE_GROWL, Score_Minus10 - if_move MOVE_ROAR, Score_Minus10 - if_move MOVE_SING, Score_Minus10 - if_move MOVE_SUPERSONIC, Score_Minus10 - if_move MOVE_SCREECH, Score_Minus10 - if_move MOVE_SNORE, Score_Minus10 - if_move MOVE_UPROAR, Score_Minus10 - if_move MOVE_METAL_SOUND, Score_Minus10 - if_move MOVE_GRASS_WHISTLE, Score_Minus10 - -AI_CheckBadMove_CheckEffect:: - if_effect EFFECT_SLEEP, AI_CBM_Sleep - if_effect EFFECT_EXPLOSION, AI_CBM_Explosion - if_effect EFFECT_DREAM_EATER, AI_CBM_DreamEater - if_effect EFFECT_ATTACK_UP, AI_CBM_AttackUp - if_effect EFFECT_DEFENSE_UP, AI_CBM_DefenseUp - if_effect EFFECT_SPEED_UP, AI_CBM_SpeedUp - if_effect EFFECT_SPECIAL_ATTACK_UP, AI_CBM_SpAtkUp - if_effect EFFECT_SPECIAL_DEFENSE_UP, AI_CBM_SpDefUp - if_effect EFFECT_ACCURACY_UP, AI_CBM_AccUp - if_effect EFFECT_EVASION_UP, AI_CBM_EvasionUp - if_effect EFFECT_ATTACK_DOWN, AI_CBM_AttackDown - if_effect EFFECT_DEFENSE_DOWN, AI_CBM_DefenseDown - if_effect EFFECT_SPEED_DOWN, AI_CBM_SpeedDown - if_effect EFFECT_SPECIAL_ATTACK_DOWN, AI_CBM_SpAtkDown - if_effect EFFECT_SPECIAL_DEFENSE_DOWN, AI_CBM_SpDefDown - if_effect EFFECT_ACCURACY_DOWN, AI_CBM_AccDown - if_effect EFFECT_EVASION_DOWN, AI_CBM_EvasionDown - if_effect EFFECT_HAZE, AI_CBM_Haze - if_effect EFFECT_BIDE, AI_CBM_HighRiskForDamage - if_effect EFFECT_ROAR, AI_CBM_Roar - if_effect EFFECT_TOXIC, AI_CBM_Poison - if_effect EFFECT_LIGHT_SCREEN, AI_CBM_LightScreen - if_effect EFFECT_OHKO, AI_CBM_OneHitKO - if_effect EFFECT_RAZOR_WIND, AI_CBM_HighRiskForDamage - if_effect EFFECT_SUPER_FANG, AI_CBM_HighRiskForDamage - if_effect EFFECT_MIST, AI_CBM_Mist - if_effect EFFECT_FOCUS_ENERGY, AI_CBM_FocusEnergy - if_effect EFFECT_CONFUSE, AI_CBM_Confuse - if_effect EFFECT_ATTACK_UP_2, AI_CBM_AttackUp - if_effect EFFECT_DEFENSE_UP_2, AI_CBM_DefenseUp - if_effect EFFECT_SPEED_UP_2, AI_CBM_SpeedUp - if_effect EFFECT_SPECIAL_ATTACK_UP_2, AI_CBM_SpAtkUp - if_effect EFFECT_SPECIAL_DEFENSE_UP_2, AI_CBM_SpDefUp - if_effect EFFECT_ACCURACY_UP_2, AI_CBM_AccUp - if_effect EFFECT_EVASION_UP_2, AI_CBM_EvasionUp - if_effect EFFECT_ATTACK_DOWN_2, AI_CBM_AttackDown - if_effect EFFECT_DEFENSE_DOWN_2, AI_CBM_DefenseDown - if_effect EFFECT_SPEED_DOWN_2, AI_CBM_SpeedDown - if_effect EFFECT_SPECIAL_ATTACK_DOWN_2, AI_CBM_SpAtkDown - if_effect EFFECT_SPECIAL_DEFENSE_DOWN_2, AI_CBM_SpDefDown - if_effect EFFECT_ACCURACY_DOWN_2, AI_CBM_AccDown - if_effect EFFECT_EVASION_DOWN_2, AI_CBM_EvasionDown - if_effect EFFECT_REFLECT, AI_CBM_Reflect - if_effect EFFECT_POISON, AI_CBM_Poison - if_effect EFFECT_PARALYZE, AI_CBM_Paralyze - if_effect EFFECT_SUBSTITUTE, AI_CBM_Substitute - if_effect EFFECT_RECHARGE, AI_CBM_HighRiskForDamage - if_effect EFFECT_LEECH_SEED, AI_CBM_LeechSeed - if_effect EFFECT_DISABLE, AI_CBM_Disable - if_effect EFFECT_LEVEL_DAMAGE, AI_CBM_HighRiskForDamage - if_effect EFFECT_PSYWAVE, AI_CBM_HighRiskForDamage - if_effect EFFECT_COUNTER, AI_CBM_HighRiskForDamage - if_effect EFFECT_ENCORE, AI_CBM_Encore - if_effect EFFECT_SNORE, AI_CBM_DamageDuringSleep - if_effect EFFECT_SLEEP_TALK, AI_CBM_DamageDuringSleep - if_effect EFFECT_FLAIL, AI_CBM_HighRiskForDamage - if_effect EFFECT_MEAN_LOOK, AI_CBM_CantEscape - if_effect EFFECT_NIGHTMARE, AI_CBM_Nightmare - if_effect EFFECT_MINIMIZE, AI_CBM_EvasionUp - if_effect EFFECT_CURSE, AI_CBM_Curse - if_effect EFFECT_SPIKES, AI_CBM_Spikes - if_effect EFFECT_FORESIGHT, AI_CBM_Foresight - if_effect EFFECT_PERISH_SONG, AI_CBM_PerishSong - if_effect EFFECT_SANDSTORM, AI_CBM_Sandstorm - if_effect EFFECT_SWAGGER, AI_CBM_Confuse - if_effect EFFECT_ATTRACT, AI_CBM_Attract - if_effect EFFECT_RETURN, AI_CBM_HighRiskForDamage - if_effect EFFECT_PRESENT, AI_CBM_HighRiskForDamage - if_effect EFFECT_FRUSTRATION, AI_CBM_HighRiskForDamage - if_effect EFFECT_SAFEGUARD, AI_CBM_Safeguard - if_effect EFFECT_MAGNITUDE, AI_CBM_Magnitude - if_effect EFFECT_BATON_PASS, AI_CBM_BatonPass - if_effect EFFECT_SONICBOOM, AI_CBM_HighRiskForDamage - if_effect EFFECT_RAIN_DANCE, AI_CBM_RainDance - if_effect EFFECT_SUNNY_DAY, AI_CBM_SunnyDay - if_effect EFFECT_BELLY_DRUM, AI_CBM_BellyDrum - if_effect EFFECT_PSYCH_UP, AI_CBM_Haze - if_effect EFFECT_MIRROR_COAT, AI_CBM_HighRiskForDamage - if_effect EFFECT_SKULL_BASH, AI_CBM_HighRiskForDamage - if_effect EFFECT_FUTURE_SIGHT, AI_CBM_FutureSight - if_effect EFFECT_TELEPORT, Score_Minus10 - if_effect EFFECT_DEFENSE_CURL, AI_CBM_DefenseUp - if_effect EFFECT_FAKE_OUT, AI_CBM_FakeOut - if_effect EFFECT_STOCKPILE, AI_CBM_Stockpile - if_effect EFFECT_SPIT_UP, AI_CBM_SpitUpAndSwallow - if_effect EFFECT_SWALLOW, AI_CBM_SpitUpAndSwallow - if_effect EFFECT_HAIL, AI_CBM_Hail - if_effect EFFECT_TORMENT, AI_CBM_Torment - if_effect EFFECT_FLATTER, AI_CBM_Confuse - if_effect EFFECT_WILL_O_WISP, AI_CBM_WillOWisp - if_effect EFFECT_MEMENTO, AI_CBM_Memento - if_effect EFFECT_FOCUS_PUNCH, AI_CBM_HighRiskForDamage - if_effect EFFECT_HELPING_HAND, AI_CBM_HelpingHand - if_effect EFFECT_TRICK, AI_CBM_TrickAndKnockOff - if_effect EFFECT_INGRAIN, AI_CBM_Ingrain - if_effect EFFECT_SUPERPOWER, AI_CBM_HighRiskForDamage - if_effect EFFECT_RECYCLE, AI_CBM_Recycle - if_effect EFFECT_KNOCK_OFF, AI_CBM_TrickAndKnockOff - if_effect EFFECT_ENDEAVOR, AI_CBM_HighRiskForDamage - if_effect EFFECT_IMPRISON, AI_CBM_Imprison - if_effect EFFECT_REFRESH, AI_CBM_Refresh - if_effect EFFECT_LOW_KICK, AI_CBM_HighRiskForDamage - if_effect EFFECT_MUD_SPORT, AI_CBM_MudSport - if_effect EFFECT_TICKLE, AI_CBM_Tickle - if_effect EFFECT_COSMIC_POWER, AI_CBM_CosmicPower - if_effect EFFECT_BULK_UP, AI_CBM_BulkUp - if_effect EFFECT_WATER_SPORT, AI_CBM_WaterSport - if_effect EFFECT_CALM_MIND, AI_CBM_CalmMind - if_effect EFFECT_DRAGON_DANCE, AI_CBM_DragonDance - end - -AI_CBM_Sleep:: - get_ability AI_TARGET - if_equal ABILITY_INSOMNIA, Score_Minus10 - if_equal ABILITY_VITAL_SPIRIT, Score_Minus10 - if_status AI_TARGET, STATUS1_ANY, Score_Minus10 -@ if_side_affecting AI_TARGET, SIDE_STATUS_SAFEGUARD, Score_Minus10 @ Improvement in Emerald - end - -AI_CBM_Explosion:: - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_DAMP, Score_Minus10 - count_alive_pokemon AI_USER - if_not_equal 0, AI_CBM_Explosion_End - count_alive_pokemon AI_TARGET - if_not_equal 0, Score_Minus10 - goto Score_Minus1 - -AI_CBM_Explosion_End:: - end - -AI_CBM_Nightmare:: - if_status2 AI_TARGET, STATUS2_NIGHTMARE, Score_Minus10 - if_not_status AI_TARGET, STATUS1_SLEEP, Score_Minus8 - end - -AI_CBM_DreamEater:: - if_not_status AI_TARGET, STATUS1_SLEEP, Score_Minus8 - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - end - -AI_CBM_BellyDrum:: - if_hp_less_than AI_USER, 51, Score_Minus10 - -AI_CBM_AttackUp:: - if_stat_level_equal AI_USER, STAT_ATK, 12, Score_Minus10 - end - -AI_CBM_DefenseUp:: - if_stat_level_equal AI_USER, STAT_DEF, 12, Score_Minus10 - end - -AI_CBM_SpeedUp:: - if_stat_level_equal AI_USER, STAT_SPEED, 12, Score_Minus10 - end - -AI_CBM_SpAtkUp:: - if_stat_level_equal AI_USER, STAT_SPATK, 12, Score_Minus10 - end - -AI_CBM_SpDefUp:: - if_stat_level_equal AI_USER, STAT_SPDEF, 12, Score_Minus10 - end - -AI_CBM_AccUp:: - if_stat_level_equal AI_USER, STAT_ACC, 12, Score_Minus10 - end - -AI_CBM_EvasionUp:: - if_stat_level_equal AI_USER, STAT_EVASION, 12, Score_Minus10 - end - -AI_CBM_AttackDown:: - if_stat_level_equal AI_TARGET, STAT_ATK, 0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_HYPER_CUTTER, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_DefenseDown:: - if_stat_level_equal AI_TARGET, STAT_DEF, 0, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_SpeedDown:: - if_stat_level_equal AI_TARGET, STAT_SPEED, 0, Score_Minus10 -@ get_ability AI_TARGET @ Improvement in Emerald -@ if_equal ABILITY_SPEED_BOOST, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_SpAtkDown:: - if_stat_level_equal AI_TARGET, STAT_SPATK, 0, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_SpDefDown:: - if_stat_level_equal AI_TARGET, STAT_SPDEF, 0, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_AccDown:: - if_stat_level_equal AI_TARGET, STAT_ACC, 0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_KEEN_EYE, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_EvasionDown:: - if_stat_level_equal AI_TARGET, STAT_EVASION, 0, Score_Minus10 - -CheckIfAbilityBlocksStatChange:: - get_ability AI_TARGET - if_equal ABILITY_CLEAR_BODY, Score_Minus10 - if_equal ABILITY_WHITE_SMOKE, Score_Minus10 - end - -AI_CBM_Haze:: - if_stat_level_less_than AI_USER, STAT_ATK, 6, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_DEF, 6, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_SPEED, 6, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_SPATK, 6, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_SPDEF, 6, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_ACC, 6, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_EVASION, 6, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_ATK, 6, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_DEF, 6, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_SPEED, 6, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_SPATK, 6, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_SPDEF, 6, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_ACC, 6, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_EVASION, 6, AI_CBM_Haze_End - goto Score_Minus10 - -AI_CBM_Haze_End:: - end - -AI_CBM_Roar:: - count_alive_pokemon AI_TARGET - if_equal 0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_SUCTION_CUPS, Score_Minus10 - end - -AI_CBM_Poison:: - get_target_type1 - if_equal TYPE_STEEL, Score_Minus10 - if_equal TYPE_POISON, Score_Minus10 - get_target_type2 - if_equal TYPE_STEEL, Score_Minus10 - if_equal TYPE_POISON, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_IMMUNITY, Score_Minus10 - if_status AI_TARGET, STATUS1_ANY, Score_Minus10 -@ if_side_affecting AI_TARGET, SIDE_STATUS_SAFEGUARD, Score_Minus10 @ Improvement in Emerald - end - -AI_CBM_LightScreen:: - if_side_affecting AI_USER, SIDE_STATUS_LIGHTSCREEN, Score_Minus8 - end - -AI_CBM_OneHitKO:: - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_STURDY, Score_Minus10 - if_level_cond 1, Score_Minus10 - end - -AI_CBM_Magnitude:: - get_ability AI_TARGET - if_equal ABILITY_LEVITATE, Score_Minus10 - -AI_CBM_HighRiskForDamage:: - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - get_ability AI_TARGET - if_not_equal ABILITY_WONDER_GUARD, AI_CBM_HighRiskForDamage_End - if_type_effectiveness AI_EFFECTIVENESS_x2, AI_CBM_HighRiskForDamage_End - goto Score_Minus10 - -AI_CBM_HighRiskForDamage_End:: - end - -AI_CBM_Mist:: - if_side_affecting AI_USER, SIDE_STATUS_MIST, Score_Minus8 - end - -AI_CBM_FocusEnergy:: - if_status2 AI_USER, STATUS2_FOCUS_ENERGY, Score_Minus10 - end - -AI_CBM_Confuse:: - if_status2 AI_TARGET, STATUS2_CONFUSION, Score_Minus5 - get_ability AI_TARGET - if_equal ABILITY_OWN_TEMPO, Score_Minus10 -@ if_side_affecting AI_TARGET, SIDE_STATUS_SAFEGUARD, Score_Minus10 @ Improvement in Emerald - end - -AI_CBM_Reflect:: - if_side_affecting AI_USER, SIDE_STATUS_REFLECT, Score_Minus8 - end - -AI_CBM_Paralyze:: - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_LIMBER, Score_Minus10 - if_status AI_TARGET, STATUS1_ANY, Score_Minus10 -@ if_side_affecting AI_TARGET, SIDE_STATUS_SAFEGUARD, Score_Minus10 @ Improvement in Emerald - end - -AI_CBM_Substitute:: - if_status2 AI_USER, STATUS2_SUBSTITUTE, Score_Minus8 - if_hp_less_than AI_USER, 26, Score_Minus10 - end - -AI_CBM_LeechSeed:: - if_status3 AI_TARGET, STATUS3_LEECHSEED, Score_Minus10 - get_target_type1 - if_equal TYPE_GRASS, Score_Minus10 - get_target_type2 - if_equal TYPE_GRASS, Score_Minus10 - end - -AI_CBM_Disable:: - if_any_move_disabled AI_TARGET, Score_Minus8 - end - -AI_CBM_Encore:: - if_any_move_encored AI_TARGET, Score_Minus8 - end - -AI_CBM_DamageDuringSleep:: - if_not_status AI_USER, STATUS1_SLEEP, Score_Minus8 - end - -AI_CBM_CantEscape:: - if_status2 AI_TARGET, STATUS2_ESCAPE_PREVENTION, Score_Minus10 - end - -AI_CBM_Curse:: - if_stat_level_equal AI_USER, STAT_ATK, 12, Score_Minus10 - if_stat_level_equal AI_USER, STAT_DEF, 12, Score_Minus8 - end - -AI_CBM_Spikes:: - if_side_affecting AI_TARGET, SIDE_STATUS_SPIKES, Score_Minus10 - end - -AI_CBM_Foresight:: - if_status2 AI_TARGET, STATUS2_FORESIGHT, Score_Minus10 - end - -AI_CBM_PerishSong:: - if_status3 AI_TARGET, STATUS3_PERISH_SONG, Score_Minus10 - end - -AI_CBM_Sandstorm:: - get_weather - if_equal AI_WEATHER_SANDSTORM, Score_Minus8 - end - -AI_CBM_Attract:: - if_status2 AI_TARGET, STATUS2_INFATUATION, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_OBLIVIOUS, Score_Minus10 - get_gender AI_USER - if_equal MON_MALE, AI_CBM_Attract_CheckIfTargetIsFemale - if_equal MON_FEMALE, AI_CBM_Attract_CheckIfTargetIsMale - goto Score_Minus10 - -AI_CBM_Attract_CheckIfTargetIsFemale:: - get_gender AI_TARGET - if_equal MON_FEMALE, AI_CBM_Attract_End - goto Score_Minus10 - -AI_CBM_Attract_CheckIfTargetIsMale:: - get_gender AI_TARGET - if_equal MON_MALE, AI_CBM_Attract_End - goto Score_Minus10 - -AI_CBM_Attract_End:: - end - -AI_CBM_Safeguard:: - if_side_affecting AI_USER, SIDE_STATUS_SAFEGUARD, Score_Minus8 - end - -AI_CBM_Memento:: - if_stat_level_equal AI_TARGET, STAT_ATK, 0, Score_Minus10 - if_stat_level_equal AI_TARGET, STAT_SPATK, 0, Score_Minus8 - -AI_CBM_BatonPass:: - count_alive_pokemon AI_USER - if_equal 0, Score_Minus10 - end - -AI_CBM_RainDance:: - get_weather - if_equal AI_WEATHER_RAIN, Score_Minus8 - end - -AI_CBM_SunnyDay:: - get_weather - if_equal AI_WEATHER_SUN, Score_Minus8 - end - -AI_CBM_FutureSight:: - if_side_affecting AI_TARGET, SIDE_STATUS_FUTUREATTACK, Score_Minus10 -@ if_side_affecting AI_USER, SIDE_STATUS_FUTUREATTACK, Score_Minus12 @ Improvement in Emerald - end - -AI_CBM_FakeOut:: - is_first_turn_for AI_USER - if_equal 0, Score_Minus10 - end - -AI_CBM_Stockpile:: - get_stockpile_count AI_USER - if_equal 3, Score_Minus10 - end - -AI_CBM_SpitUpAndSwallow:: - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - get_stockpile_count AI_USER - if_equal 0, Score_Minus10 - end - -AI_CBM_Hail:: - get_weather - if_equal AI_WEATHER_HAIL, Score_Minus8 - end - -AI_CBM_Torment:: - if_status2 AI_TARGET, STATUS2_TORMENT, Score_Minus10 - end - -AI_CBM_WillOWisp:: - get_ability AI_TARGET - if_equal ABILITY_WATER_VEIL, Score_Minus10 - if_status AI_TARGET, STATUS1_ANY, Score_Minus10 - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - if_type_effectiveness AI_EFFECTIVENESS_x0_5, Score_Minus10 - if_type_effectiveness AI_EFFECTIVENESS_x0_25, Score_Minus10 -@ if_side_affecting AI_TARGET, SIDE_STATUS_SAFEGUARD, Score_Minus10 @ Improvement in Emerald - end - -AI_CBM_HelpingHand:: - if_not_double_battle Score_Minus10 - end - -AI_CBM_TrickAndKnockOff:: - get_ability AI_TARGET - if_equal ABILITY_STICKY_HOLD, Score_Minus10 - end - -AI_CBM_Ingrain:: - if_status3 AI_USER, STATUS3_ROOTED, Score_Minus10 - end - -AI_CBM_Recycle:: - get_used_held_item AI_USER - if_equal ITEM_NONE, Score_Minus10 - end - -AI_CBM_Imprison:: - if_status3 AI_USER, STATUS3_IMPRISONED_OTHERS, Score_Minus10 - end - -AI_CBM_Refresh:: - if_not_status AI_USER, STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON, Score_Minus10 - end - -AI_CBM_MudSport:: - if_status4 AI_USER, STATUS4_MUD_SPORT, Score_Minus10 - end - -AI_CBM_Tickle:: - if_stat_level_equal AI_TARGET, STAT_ATK, 0, Score_Minus10 - if_stat_level_equal AI_TARGET, STAT_DEF, 0, Score_Minus8 - end - -AI_CBM_CosmicPower:: - if_stat_level_equal AI_USER, STAT_DEF, 12, Score_Minus10 - if_stat_level_equal AI_USER, STAT_SPDEF, 12, Score_Minus8 - end - -AI_CBM_BulkUp:: - if_stat_level_equal AI_USER, STAT_ATK, 12, Score_Minus10 - if_stat_level_equal AI_USER, STAT_DEF, 12, Score_Minus8 - end - -AI_CBM_WaterSport:: - if_status4 AI_USER, STATUS4_WATER_SPORT, Score_Minus10 - end - -AI_CBM_CalmMind:: - if_stat_level_equal AI_USER, STAT_SPATK, 12, Score_Minus10 - if_stat_level_equal AI_USER, STAT_SPDEF, 12, Score_Minus8 - end - -AI_CBM_DragonDance:: - if_stat_level_equal AI_USER, STAT_ATK, 12, Score_Minus10 - if_stat_level_equal AI_USER, STAT_SPEED, 12, Score_Minus8 - end - -Score_Minus1:: - score -1 - end - -Score_Minus2:: - score -2 - end - -Score_Minus3:: - score -3 - end - -Score_Minus5:: - score -5 - end - -Score_Minus8:: - score -8 - end - -Score_Minus10:: - score -10 - end - -Score_Minus12:: - score -12 - end - -Score_Plus1:: - score +1 - end - -Score_Plus2:: - score +2 - end - -Score_Plus3:: - score +3 - end - -Score_Plus5:: - score +5 - end - -@ Improvement in Emerald -@Score_Plus10:: -@ score +10 -@ end - -AI_CheckViability:: - if_effect EFFECT_SLEEP, AI_CV_Sleep - if_effect EFFECT_ABSORB, AI_CV_Absorb - if_effect EFFECT_EXPLOSION, AI_CV_SelfKO - if_effect EFFECT_DREAM_EATER, AI_CV_DreamEater - if_effect EFFECT_MIRROR_MOVE, AI_CV_MirrorMove - if_effect EFFECT_ATTACK_UP, AI_CV_AttackUp - if_effect EFFECT_DEFENSE_UP, AI_CV_DefenseUp - if_effect EFFECT_SPEED_UP, AI_CV_SpeedUp - if_effect EFFECT_SPECIAL_ATTACK_UP, AI_CV_SpAtkUp - if_effect EFFECT_SPECIAL_DEFENSE_UP, AI_CV_SpDefUp - if_effect EFFECT_ACCURACY_UP, AI_CV_AccuracyUp - if_effect EFFECT_EVASION_UP, AI_CV_EvasionUp - if_effect EFFECT_ALWAYS_HIT, AI_CV_AlwaysHit - if_effect EFFECT_ATTACK_DOWN, AI_CV_AttackDown - if_effect EFFECT_DEFENSE_DOWN, AI_CV_DefenseDown - if_effect EFFECT_SPEED_DOWN, AI_CV_SpeedDown - if_effect EFFECT_SPECIAL_ATTACK_DOWN, AI_CV_SpAtkDown - if_effect EFFECT_SPECIAL_DEFENSE_DOWN, AI_CV_SpDefDown - if_effect EFFECT_ACCURACY_DOWN, AI_CV_AccuracyDown - if_effect EFFECT_EVASION_DOWN, AI_CV_EvasionDown - if_effect EFFECT_HAZE, AI_CV_Haze - if_effect EFFECT_BIDE, AI_CV_Bide - if_effect EFFECT_ROAR, AI_CV_Roar - if_effect EFFECT_CONVERSION, AI_CV_Conversion - if_effect EFFECT_RESTORE_HP, AI_CV_Heal - if_effect EFFECT_TOXIC, AI_CV_Toxic - if_effect EFFECT_LIGHT_SCREEN, AI_CV_LightScreen - if_effect EFFECT_REST, AI_CV_Rest - if_effect EFFECT_OHKO, AI_CV_OneHitKO - if_effect EFFECT_RAZOR_WIND, AI_CV_ChargeUpMove - if_effect EFFECT_SUPER_FANG, AI_CV_SuperFang - if_effect EFFECT_TRAP, AI_CV_Trap - if_effect EFFECT_HIGH_CRITICAL, AI_CV_HighCrit - if_effect EFFECT_CONFUSE, AI_CV_Confuse - if_effect EFFECT_ATTACK_UP_2, AI_CV_AttackUp - if_effect EFFECT_DEFENSE_UP_2, AI_CV_DefenseUp - if_effect EFFECT_SPEED_UP_2, AI_CV_SpeedUp - if_effect EFFECT_SPECIAL_ATTACK_UP_2, AI_CV_SpAtkUp - if_effect EFFECT_SPECIAL_DEFENSE_UP_2, AI_CV_SpDefUp - if_effect EFFECT_ACCURACY_UP_2, AI_CV_AccuracyUp - if_effect EFFECT_EVASION_UP_2, AI_CV_EvasionUp - if_effect EFFECT_ATTACK_DOWN_2, AI_CV_AttackDown - if_effect EFFECT_DEFENSE_DOWN_2, AI_CV_DefenseDown - if_effect EFFECT_SPEED_DOWN_2, AI_CV_SpeedDown - if_effect EFFECT_SPECIAL_ATTACK_DOWN_2, AI_CV_SpAtkDown - if_effect EFFECT_SPECIAL_DEFENSE_DOWN_2, AI_CV_SpDefDown - if_effect EFFECT_ACCURACY_DOWN_2, AI_CV_AccuracyDown - if_effect EFFECT_EVASION_DOWN_2, AI_CV_EvasionDown - if_effect EFFECT_REFLECT, AI_CV_Reflect - if_effect EFFECT_POISON, AI_CV_Poison - if_effect EFFECT_PARALYZE, AI_CV_Paralyze - @ if_effect EFFECT_SWAGGER, AI_CV_Swagger @ Improvement in Emerald - if_effect EFFECT_SPEED_DOWN_HIT, AI_CV_SpeedDownFromChance - if_effect EFFECT_SKY_ATTACK, AI_CV_ChargeUpMove - if_effect EFFECT_VITAL_THROW, AI_CV_VitalThrow - if_effect EFFECT_SUBSTITUTE, AI_CV_Substitute - if_effect EFFECT_RECHARGE, AI_CV_Recharge - if_effect EFFECT_LEECH_SEED, AI_CV_Toxic - if_effect EFFECT_DISABLE, AI_CV_Disable - if_effect EFFECT_COUNTER, AI_CV_Counter - if_effect EFFECT_ENCORE, AI_CV_Encore - if_effect EFFECT_PAIN_SPLIT, AI_CV_PainSplit - if_effect EFFECT_SNORE, AI_CV_Snore - if_effect EFFECT_LOCK_ON, AI_CV_LockOn - if_effect EFFECT_SLEEP_TALK, AI_CV_SleepTalk - if_effect EFFECT_DESTINY_BOND, AI_CV_DestinyBond - if_effect EFFECT_FLAIL, AI_CV_Flail - if_effect EFFECT_HEAL_BELL, AI_CV_HealBell - if_effect EFFECT_THIEF, AI_CV_Thief - if_effect EFFECT_MEAN_LOOK, AI_CV_Trap - if_effect EFFECT_MINIMIZE, AI_CV_EvasionUp - if_effect EFFECT_CURSE, AI_CV_Curse - if_effect EFFECT_PROTECT, AI_CV_Protect - if_effect EFFECT_FORESIGHT, AI_CV_Foresight - if_effect EFFECT_ENDURE, AI_CV_Endure - if_effect EFFECT_BATON_PASS, AI_CV_BatonPass - if_effect EFFECT_PURSUIT, AI_CV_Pursuit - if_effect EFFECT_MORNING_SUN, AI_CV_HealWeather - if_effect EFFECT_SYNTHESIS, AI_CV_HealWeather - if_effect EFFECT_MOONLIGHT, AI_CV_HealWeather - if_effect EFFECT_RAIN_DANCE, AI_CV_RainDance - if_effect EFFECT_SUNNY_DAY, AI_CV_SunnyDay - if_effect EFFECT_BELLY_DRUM, AI_CV_BellyDrum - if_effect EFFECT_PSYCH_UP, AI_CV_PsychUp - if_effect EFFECT_MIRROR_COAT, AI_CV_MirrorCoat - if_effect EFFECT_SKULL_BASH, AI_CV_ChargeUpMove - if_effect EFFECT_SOLAR_BEAM, AI_CV_ChargeUpMove - if_effect EFFECT_SEMI_INVULNERABLE, AI_CV_SemiInvulnerable - if_effect EFFECT_SOFTBOILED, AI_CV_Heal - if_effect EFFECT_FAKE_OUT, AI_CV_FakeOut - if_effect EFFECT_SPIT_UP, AI_CV_SpitUp - if_effect EFFECT_SWALLOW, AI_CV_Heal - if_effect EFFECT_HAIL, AI_CV_Hail - if_effect EFFECT_FLATTER, AI_CV_Flatter - if_effect EFFECT_MEMENTO, AI_CV_SelfKO - if_effect EFFECT_FACADE, AI_CV_Facade - if_effect EFFECT_FOCUS_PUNCH, AI_CV_FocusPunch - if_effect EFFECT_SMELLINGSALT, AI_CV_SmellingSalt - if_effect EFFECT_TRICK, AI_CV_Trick - if_effect EFFECT_ROLE_PLAY, AI_CV_ChangeSelfAbility - if_effect EFFECT_SUPERPOWER, AI_CV_Superpower - if_effect EFFECT_MAGIC_COAT, AI_CV_MagicCoat - if_effect EFFECT_RECYCLE, AI_CV_Recycle - if_effect EFFECT_REVENGE, AI_CV_Revenge - if_effect EFFECT_BRICK_BREAK, AI_CV_BrickBreak - if_effect EFFECT_KNOCK_OFF, AI_CV_KnockOff - if_effect EFFECT_ENDEAVOR, AI_CV_Endeavor - if_effect EFFECT_ERUPTION, AI_CV_Eruption - if_effect EFFECT_SKILL_SWAP, AI_CV_ChangeSelfAbility - if_effect EFFECT_IMPRISON, AI_CV_Imprison - if_effect EFFECT_REFRESH, AI_CV_Refresh - if_effect EFFECT_SNATCH, AI_CV_Snatch - if_effect EFFECT_BLAZE_KICK, AI_CV_HighCrit - if_effect EFFECT_MUD_SPORT, AI_CV_MudSport - if_effect EFFECT_OVERHEAT, AI_CV_Overheat - if_effect EFFECT_TICKLE, AI_CV_DefenseDown - if_effect EFFECT_COSMIC_POWER, AI_CV_SpDefUp - if_effect EFFECT_BULK_UP, AI_CV_DefenseUp - if_effect EFFECT_POISON_TAIL, AI_CV_HighCrit - if_effect EFFECT_WATER_SPORT, AI_CV_WaterSport - if_effect EFFECT_CALM_MIND, AI_CV_SpDefUp - if_effect EFFECT_DRAGON_DANCE, AI_CV_DragonDance - end - -AI_CV_Sleep:: - if_has_move_with_effect AI_TARGET, EFFECT_DREAM_EATER, AI_CV_SleepEncourageSlpDamage - if_has_move_with_effect AI_TARGET, EFFECT_NIGHTMARE, AI_CV_SleepEncourageSlpDamage - goto AI_CV_Sleep_End - -AI_CV_SleepEncourageSlpDamage:: - if_random_less_than 128, AI_CV_Sleep_End - score +1 - -AI_CV_Sleep_End:: - end - -AI_CV_Absorb:: - if_type_effectiveness AI_EFFECTIVENESS_x0_5, AI_CV_AbsorbEncourageMaybe - if_type_effectiveness AI_EFFECTIVENESS_x0_25, AI_CV_AbsorbEncourageMaybe - goto AI_CV_Absorb_End - -AI_CV_AbsorbEncourageMaybe:: - if_random_less_than 50, AI_CV_Absorb_End - score -3 - -AI_CV_Absorb_End:: - end - -AI_CV_SelfKO:: - if_stat_level_less_than AI_TARGET, STAT_EVASION, 7, AI_CV_SelfKO_Encourage1 - score -1 - if_stat_level_less_than AI_TARGET, STAT_EVASION, 10, AI_CV_SelfKO_Encourage1 - if_random_less_than 128, AI_CV_SelfKO_Encourage1 - score -1 - -AI_CV_SelfKO_Encourage1:: - if_hp_less_than AI_USER, 80, AI_CV_SelfKO_Encourage2 - if_target_faster AI_CV_SelfKO_Encourage2 - if_random_less_than 50, AI_CV_SelfKO_End - goto Score_Minus3 - -AI_CV_SelfKO_Encourage2:: - if_hp_more_than AI_USER, 50, AI_CV_SelfKO_Encourage4 - if_random_less_than 128, AI_CV_SelfKO_Encourage3 - score +1 - -AI_CV_SelfKO_Encourage3:: - if_hp_more_than AI_USER, 30, AI_CV_SelfKO_End - if_random_less_than 50, AI_CV_SelfKO_End - score +1 - goto AI_CV_SelfKO_End - -AI_CV_SelfKO_Encourage4:: - if_random_less_than 50, AI_CV_SelfKO_End - score -1 - -AI_CV_SelfKO_End:: - end - -AI_CV_DreamEater:: - if_type_effectiveness AI_EFFECTIVENESS_x0_25, AI_CV_DreamEater_ScoreDown1 - if_type_effectiveness AI_EFFECTIVENESS_x0_5, AI_CV_DreamEater_ScoreDown1 - goto AI_CV_DreamEater_End - -AI_CV_DreamEater_ScoreDown1:: - score -1 - -AI_CV_DreamEater_End:: - end - -AI_CV_MirrorMove:: - if_target_faster AI_CV_MirrorMove2 - get_last_used_move AI_TARGET - if_not_in_hwords AI_CV_MirrorMove_EncouragedMovesToMirror, AI_CV_MirrorMove2 - if_random_less_than 128, AI_CV_MirrorMove_End - score +2 - goto AI_CV_MirrorMove_End - -AI_CV_MirrorMove2:: - get_last_used_move AI_TARGET - if_in_hwords AI_CV_MirrorMove_EncouragedMovesToMirror, AI_CV_MirrorMove_End - if_random_less_than 80, AI_CV_MirrorMove_End - score -1 - -AI_CV_MirrorMove_End:: - end - - .space 2 -AI_CV_MirrorMove_EncouragedMovesToMirror:: - .align 1 - .2byte MOVE_SLEEP_POWDER - .2byte MOVE_LOVELY_KISS - .2byte MOVE_SPORE - .2byte MOVE_HYPNOSIS - .2byte MOVE_SING - .2byte MOVE_GRASS_WHISTLE - .2byte MOVE_SHADOW_PUNCH - .2byte MOVE_SAND_ATTACK - .2byte MOVE_SMOKESCREEN - .2byte MOVE_TOXIC - .2byte MOVE_GUILLOTINE - .2byte MOVE_HORN_DRILL - .2byte MOVE_FISSURE - .2byte MOVE_SHEER_COLD - .2byte MOVE_CROSS_CHOP - .2byte MOVE_AEROBLAST - .2byte MOVE_CONFUSE_RAY - .2byte MOVE_SWEET_KISS - .2byte MOVE_SCREECH - .2byte MOVE_COTTON_SPORE - .2byte MOVE_SCARY_FACE - .2byte MOVE_FAKE_TEARS - .2byte MOVE_METAL_SOUND - .2byte MOVE_THUNDER_WAVE - .2byte MOVE_GLARE - .2byte MOVE_POISON_POWDER - .2byte MOVE_SHADOW_BALL - .2byte MOVE_DYNAMIC_PUNCH - .2byte MOVE_HYPER_BEAM - .2byte MOVE_EXTREME_SPEED - .2byte MOVE_THIEF - .2byte MOVE_COVET - .2byte MOVE_ATTRACT - .2byte MOVE_SWAGGER - .2byte MOVE_TORMENT - .2byte MOVE_FLATTER - .2byte MOVE_TRICK - .2byte MOVE_SUPERPOWER - .2byte MOVE_SKILL_SWAP - .2byte -1 - -AI_CV_AttackUp:: - if_stat_level_less_than AI_USER, STAT_ATK, 9, AI_CV_AttackUp2 - if_random_less_than 100, AI_CV_AttackUp3 - score -1 - goto AI_CV_AttackUp3 - -AI_CV_AttackUp2:: - if_hp_not_equal AI_USER, 100, AI_CV_AttackUp3 - if_random_less_than 128, AI_CV_AttackUp3 - score +2 - -AI_CV_AttackUp3:: - if_hp_more_than AI_USER, 70, AI_CV_AttackUp_End - if_hp_less_than AI_USER, 40, AI_CV_AttackUp_ScoreDown2 - if_random_less_than 40, AI_CV_AttackUp_End - -AI_CV_AttackUp_ScoreDown2:: - score -2 - -AI_CV_AttackUp_End:: - end - -AI_CV_DefenseUp:: - if_stat_level_less_than AI_USER, STAT_DEF, 9, AI_CV_DefenseUp2 - if_random_less_than 100, AI_CV_DefenseUp3 - score -1 - goto AI_CV_DefenseUp3 - -AI_CV_DefenseUp2:: - if_hp_not_equal AI_USER, 100, AI_CV_DefenseUp3 - if_random_less_than 128, AI_CV_DefenseUp3 - score +2 - -AI_CV_DefenseUp3:: - if_hp_less_than AI_USER, 70, AI_CV_DefenseUp4 - if_random_less_than 200, AI_CV_DefenseUp_End - -AI_CV_DefenseUp4:: - if_hp_less_than AI_USER, 40, AI_CV_DefenseUp_ScoreDown2 - get_last_used_move AI_TARGET - get_move_power_from_result - if_equal 0, AI_CV_DefenseUp5 - get_last_used_move AI_TARGET - get_move_type_from_result - if_not_in_bytes AI_CV_DefenseUp_PhysicalTypes, AI_CV_DefenseUp_ScoreDown2 - if_random_less_than 60, AI_CV_DefenseUp_End - -AI_CV_DefenseUp5:: - if_random_less_than 60, AI_CV_DefenseUp_End - -AI_CV_DefenseUp_ScoreDown2:: - score -2 - -AI_CV_DefenseUp_End:: - end - -AI_CV_DefenseUp_PhysicalTypes:: - .byte TYPE_NORMAL - .byte TYPE_FIGHTING - .byte TYPE_POISON - .byte TYPE_GROUND - .byte TYPE_FLYING - .byte TYPE_ROCK - .byte TYPE_BUG - .byte TYPE_GHOST - .byte TYPE_STEEL - .byte -1 - -AI_CV_SpeedUp:: - if_target_faster AI_CV_SpeedUp2 - score -3 - goto AI_CV_SpeedUp_End - -AI_CV_SpeedUp2:: - if_random_less_than 70, AI_CV_SpeedUp_End - score +3 - -AI_CV_SpeedUp_End:: - end - -AI_CV_SpAtkUp:: - if_stat_level_less_than AI_USER, STAT_SPATK, 9, AI_CV_SpAtkUp2 - if_random_less_than 100, AI_CV_SpAtkUp3 - score -1 - goto AI_CV_SpAtkUp3 - -AI_CV_SpAtkUp2:: - if_hp_not_equal AI_USER, 100, AI_CV_SpAtkUp3 - if_random_less_than 128, AI_CV_SpAtkUp3 - score +2 - -AI_CV_SpAtkUp3:: - if_hp_more_than AI_USER, 70, AI_CV_SpAtkUp_End - if_hp_less_than AI_USER, 40, AI_CV_SpAtkUp_ScoreDown2 - if_random_less_than 70, AI_CV_SpAtkUp_End - -AI_CV_SpAtkUp_ScoreDown2:: - score -2 - -AI_CV_SpAtkUp_End:: - end - -AI_CV_SpDefUp:: - if_stat_level_less_than AI_USER, STAT_SPDEF, 9, AI_CV_SpDefUp2 - if_random_less_than 100, AI_CV_SpDefUp3 - score -1 - goto AI_CV_SpDefUp3 - -AI_CV_SpDefUp2:: - if_hp_not_equal AI_USER, 100, AI_CV_SpDefUp3 - if_random_less_than 128, AI_CV_SpDefUp3 - score +2 - -AI_CV_SpDefUp3:: - if_hp_less_than AI_USER, 70, AI_CV_SpDefUp4 - if_random_less_than 200, AI_CV_SpDefUp_End - -AI_CV_SpDefUp4:: - if_hp_less_than AI_USER, 40, AI_CV_SpDefUp_ScoreDown2 - get_last_used_move AI_TARGET - get_move_power_from_result - if_equal 0, AI_CV_SpDefUp5 - get_last_used_move AI_TARGET - get_move_type_from_result - if_in_bytes AI_CV_SpDefUp_PhysicalTypes, AI_CV_SpDefUp_ScoreDown2 - if_random_less_than 60, AI_CV_SpDefUp_End - -AI_CV_SpDefUp5:: - if_random_less_than 60, AI_CV_SpDefUp_End - -AI_CV_SpDefUp_ScoreDown2:: - score -2 - -AI_CV_SpDefUp_End:: - end - -AI_CV_SpDefUp_PhysicalTypes:: - .byte TYPE_NORMAL - .byte TYPE_FIGHTING - .byte TYPE_POISON - .byte TYPE_GROUND - .byte TYPE_FLYING - .byte TYPE_ROCK - .byte TYPE_BUG - .byte TYPE_GHOST - .byte TYPE_STEEL - .byte -1 - -AI_CV_AccuracyUp:: - if_stat_level_less_than AI_USER, STAT_ACC, 9, AI_CV_AccuracyUp2 - if_random_less_than 50, AI_CV_AccuracyUp2 - score -2 - -AI_CV_AccuracyUp2:: - if_hp_more_than AI_USER, 70, AI_CV_AccuracyUp_End - score -2 - -AI_CV_AccuracyUp_End:: - end - -AI_CV_EvasionUp:: - if_hp_less_than AI_USER, 90, AI_CV_EvasionUp2 - if_random_less_than 100, AI_CV_EvasionUp2 - score +3 - -AI_CV_EvasionUp2:: - if_stat_level_less_than AI_USER, STAT_EVASION, 9, AI_CV_EvasionUp3 - if_random_less_than 128, AI_CV_EvasionUp3 - score -1 - -AI_CV_EvasionUp3:: - if_not_status AI_TARGET, STATUS1_TOXIC_POISON, AI_CV_EvasionUp5 - if_hp_more_than AI_USER, 50, AI_CV_EvasionUp4 - if_random_less_than 80, AI_CV_EvasionUp5 - -AI_CV_EvasionUp4:: - if_random_less_than 50, AI_CV_EvasionUp5 - score +3 - -AI_CV_EvasionUp5:: - if_not_status3 AI_TARGET, STATUS3_LEECHSEED, AI_CV_EvasionUp6 - if_random_less_than 70, AI_CV_EvasionUp6 - score +3 - -AI_CV_EvasionUp6:: - if_not_status3 AI_USER, STATUS3_ROOTED, AI_CV_EvasionUp7 - if_random_less_than 128, AI_CV_EvasionUp7 - score +2 - -AI_CV_EvasionUp7:: - if_not_status2 AI_TARGET, STATUS2_CURSED, AI_CV_EvasionUp8 - if_random_less_than 70, AI_CV_EvasionUp8 - score +3 - -AI_CV_EvasionUp8:: - if_hp_more_than AI_USER, 70, AI_CV_EvasionUp_End - if_stat_level_equal AI_USER, STAT_EVASION, 6, AI_CV_EvasionUp_End - if_hp_less_than AI_USER, 40, AI_CV_EvasionUp_ScoreDown2 - if_hp_less_than AI_TARGET, 40, AI_CV_EvasionUp_ScoreDown2 - if_random_less_than 70, AI_CV_EvasionUp_End - -AI_CV_EvasionUp_ScoreDown2:: - score -2 - -AI_CV_EvasionUp_End:: - end - -AI_CV_AlwaysHit:: - if_stat_level_more_than AI_TARGET, STAT_EVASION, 10, AI_CV_AlwaysHit_ScoreUp1 - if_stat_level_less_than AI_USER, STAT_ACC, 2, AI_CV_AlwaysHit_ScoreUp1 - if_stat_level_more_than AI_TARGET, STAT_EVASION, 8, AI_CV_AlwaysHit2 - if_stat_level_less_than AI_USER, STAT_ACC, 4, AI_CV_AlwaysHit2 - goto AI_CV_AlwaysHit_End - -AI_CV_AlwaysHit_ScoreUp1:: - score +1 - -AI_CV_AlwaysHit2:: - if_random_less_than 100, AI_CV_AlwaysHit_End - score +1 - -AI_CV_AlwaysHit_End:: - end - -AI_CV_AttackDown:: - if_stat_level_equal AI_TARGET, STAT_ATK, 6, AI_CV_AttackDown3 - score -1 - if_hp_more_than AI_USER, 90, AI_CV_AttackDown2 - score -1 - -AI_CV_AttackDown2:: - if_stat_level_more_than AI_TARGET, STAT_ATK, 3, AI_CV_AttackDown3 - if_random_less_than 50, AI_CV_AttackDown3 - score -2 - -AI_CV_AttackDown3:: - if_hp_more_than AI_TARGET, 70, AI_CV_AttackDown4 - score -2 - -AI_CV_AttackDown4:: - get_target_type1 - if_in_bytes AI_CV_AttackDown_PhysicalTypeList, AI_CV_AttackDown_End - get_target_type2 - if_in_bytes AI_CV_AttackDown_PhysicalTypeList, AI_CV_AttackDown_End - if_random_less_than 50, AI_CV_AttackDown_End - score -2 - -AI_CV_AttackDown_End:: - end - -@ Missing Poison, Flying, and Ghost for unknown reason -AI_CV_AttackDown_PhysicalTypeList:: - .byte TYPE_NORMAL - .byte TYPE_FIGHTING - .byte TYPE_GROUND - .byte TYPE_ROCK - .byte TYPE_BUG - .byte TYPE_STEEL - .byte -1 - -AI_CV_DefenseDown:: - if_hp_less_than AI_USER, 70, AI_CV_DefenseDown2 - if_stat_level_more_than AI_TARGET, STAT_DEF, 3, AI_CV_DefenseDown3 - -AI_CV_DefenseDown2:: - if_random_less_than 50, AI_CV_DefenseDown3 - score -2 - -AI_CV_DefenseDown3:: - if_hp_more_than AI_TARGET, 70, AI_CV_DefenseDown_End - score -2 - -AI_CV_DefenseDown_End:: - end - -AI_CV_SpeedDownFromChance:: - if_move MOVE_ICY_WIND, AI_CV_SpeedDown - if_move MOVE_ROCK_TOMB, AI_CV_SpeedDown - if_move MOVE_MUD_SHOT, AI_CV_SpeedDown - end - -AI_CV_SpeedDown:: - if_target_faster AI_CV_SpeedDown2 - score -3 - goto AI_CV_SpeedDown_End - -AI_CV_SpeedDown2:: - if_random_less_than 70, AI_CV_SpeedDown_End - score +2 - -AI_CV_SpeedDown_End:: - end - -AI_CV_SpAtkDown:: - if_stat_level_equal AI_TARGET, STAT_ATK, 6, AI_CV_SpAtkDown3 - score -1 - if_hp_more_than AI_USER, 90, AI_CV_SpAtkDown2 - score -1 - -AI_CV_SpAtkDown2:: - if_stat_level_more_than AI_TARGET, STAT_SPATK, 3, AI_CV_SpAtkDown3 - if_random_less_than 50, AI_CV_SpAtkDown3 - score -2 - -AI_CV_SpAtkDown3:: - if_hp_more_than AI_TARGET, 70, AI_CV_SpAtkDown4 - score -2 - -AI_CV_SpAtkDown4:: - get_target_type1 - if_in_bytes AI_CV_SpAtkDown_SpecialTypeList, AI_CV_SpAtkDown_End - get_target_type2 - if_in_bytes AI_CV_SpAtkDown_SpecialTypeList, AI_CV_SpAtkDown_End - if_random_less_than 50, AI_CV_SpAtkDown_End - score -2 - -AI_CV_SpAtkDown_End:: - end - -AI_CV_SpAtkDown_SpecialTypeList:: - .byte TYPE_FIRE - .byte TYPE_WATER - .byte TYPE_GRASS - .byte TYPE_ELECTRIC - .byte TYPE_PSYCHIC - .byte TYPE_ICE - .byte TYPE_DRAGON - .byte TYPE_DARK - .byte TYPE_FAIRY - .byte -1 - -AI_CV_SpDefDown:: - if_hp_less_than AI_USER, 70, AI_CV_SpDefDown2 - if_stat_level_more_than AI_TARGET, STAT_SPDEF, 3, AI_CV_SpDefDown3 - -AI_CV_SpDefDown2:: - if_random_less_than 50, AI_CV_SpDefDown3 - score -2 - -AI_CV_SpDefDown3:: - if_hp_more_than AI_TARGET, 70, AI_CV_SpDefDown_End - score -2 - -AI_CV_SpDefDown_End:: - end - -AI_CV_AccuracyDown:: - if_hp_less_than AI_USER, 70, AI_CV_AccuracyDown2 - if_hp_more_than AI_TARGET, 70, AI_CV_AccuracyDown3 - -AI_CV_AccuracyDown2:: - if_random_less_than 100, AI_CV_AccuracyDown3 - score -1 - -AI_CV_AccuracyDown3:: - if_stat_level_more_than AI_USER, STAT_ACC, 4, AI_CV_AccuracyDown4 - if_random_less_than 80, AI_CV_AccuracyDown4 - score -2 - -AI_CV_AccuracyDown4:: - if_not_status AI_TARGET, STATUS1_TOXIC_POISON, AI_CV_AccuracyDown5 - if_random_less_than 70, AI_CV_AccuracyDown5 - score +2 - -AI_CV_AccuracyDown5:: - if_not_status3 AI_TARGET, STATUS3_LEECHSEED, AI_CV_AccuracyDown6 - if_random_less_than 70, AI_CV_AccuracyDown6 - score +2 - -AI_CV_AccuracyDown6:: - if_not_status3 AI_USER, STATUS3_ROOTED, AI_CV_AccuracyDown7 - if_random_less_than 128, AI_CV_AccuracyDown7 - score +1 - -AI_CV_AccuracyDown7:: - if_not_status2 AI_TARGET, STATUS2_CURSED, AI_CV_AccuracyDown8 - if_random_less_than 70, AI_CV_AccuracyDown8 - score +2 - -AI_CV_AccuracyDown8:: - if_hp_more_than AI_USER, 70, AI_CV_AccuracyDown_End - if_stat_level_equal AI_TARGET, STAT_ACC, 6, AI_CV_AccuracyDown_End - if_hp_less_than AI_USER, 40, AI_CV_AccuracyDown_ScoreDown2 - if_hp_less_than AI_TARGET, 40, AI_CV_AccuracyDown_ScoreDown2 - if_random_less_than 70, AI_CV_AccuracyDown_End - -AI_CV_AccuracyDown_ScoreDown2:: - score -2 - -AI_CV_AccuracyDown_End:: - end - -AI_CV_EvasionDown:: - if_hp_less_than AI_USER, 70, AI_CV_EvasionDown2 - if_stat_level_more_than AI_TARGET, STAT_EVASION, 3, AI_CV_EvasionDown3 - -AI_CV_EvasionDown2:: - if_random_less_than 50, AI_CV_EvasionDown3 - score -2 - -AI_CV_EvasionDown3:: - if_hp_more_than AI_TARGET, 70, AI_CV_EvasionDown_End - score -2 - -AI_CV_EvasionDown_End:: - end - -AI_CV_Haze:: - if_stat_level_more_than AI_USER, STAT_ATK, 8, AI_CV_Haze2 - if_stat_level_more_than AI_USER, STAT_DEF, 8, AI_CV_Haze2 - if_stat_level_more_than AI_USER, STAT_SPATK, 8, AI_CV_Haze2 - if_stat_level_more_than AI_USER, STAT_SPDEF, 8, AI_CV_Haze2 - if_stat_level_more_than AI_USER, STAT_EVASION, 8, AI_CV_Haze2 - if_stat_level_less_than AI_TARGET, STAT_ATK, 4, AI_CV_Haze2 - if_stat_level_less_than AI_TARGET, STAT_DEF, 4, AI_CV_Haze2 - if_stat_level_less_than AI_TARGET, STAT_SPATK, 4, AI_CV_Haze2 - if_stat_level_less_than AI_TARGET, STAT_SPDEF, 4, AI_CV_Haze2 - if_stat_level_less_than AI_TARGET, STAT_ACC, 4, AI_CV_Haze2 - goto AI_CV_Haze3 - -AI_CV_Haze2:: - if_random_less_than 50, AI_CV_Haze3 - score -3 - -AI_CV_Haze3:: - if_stat_level_more_than AI_TARGET, STAT_ATK, 8, AI_CV_Haze4 - if_stat_level_more_than AI_TARGET, STAT_DEF, 8, AI_CV_Haze4 - if_stat_level_more_than AI_TARGET, STAT_SPATK, 8, AI_CV_Haze4 - if_stat_level_more_than AI_TARGET, STAT_SPDEF, 8, AI_CV_Haze4 - if_stat_level_more_than AI_TARGET, STAT_EVASION, 8, AI_CV_Haze4 - if_stat_level_less_than AI_USER, STAT_ATK, 4, AI_CV_Haze4 - if_stat_level_less_than AI_USER, STAT_DEF, 4, AI_CV_Haze4 - if_stat_level_less_than AI_USER, STAT_SPATK, 4, AI_CV_Haze4 - if_stat_level_less_than AI_USER, STAT_SPDEF, 4, AI_CV_Haze4 - if_stat_level_less_than AI_USER, STAT_ACC, 4, AI_CV_Haze4 - if_random_less_than 50, AI_CV_Haze_End - score -1 - goto AI_CV_Haze_End - -AI_CV_Haze4:: - if_random_less_than 50, AI_CV_Haze_End - score +3 - -AI_CV_Haze_End:: - end - -AI_CV_Bide:: - if_hp_more_than AI_USER, 90, AI_CV_Bide_End - score -2 - -AI_CV_Bide_End:: - end - -AI_CV_Roar:: - if_stat_level_more_than AI_TARGET, STAT_ATK, 8, AI_CV_Roar2 - if_stat_level_more_than AI_TARGET, STAT_DEF, 8, AI_CV_Roar2 - if_stat_level_more_than AI_TARGET, STAT_SPATK, 8, AI_CV_Roar2 - if_stat_level_more_than AI_TARGET, STAT_SPDEF, 8, AI_CV_Roar2 - if_stat_level_more_than AI_TARGET, STAT_EVASION, 8, AI_CV_Roar2 - score -3 - goto AI_CV_Roar_End - -AI_CV_Roar2:: - if_random_less_than 128, AI_CV_Roar_End - score +2 - -AI_CV_Roar_End:: - end - -AI_CV_Conversion:: - if_hp_more_than AI_USER, 90, AI_CV_Conversion2 - score -2 - -AI_CV_Conversion2:: - get_turn_count - if_equal 0, AI_CV_Conversion_End - if_random_less_than 200, Score_Minus2 - -AI_CV_Conversion_End:: - end - -AI_CV_HealWeather:: - get_weather - if_equal AI_WEATHER_HAIL, AI_CV_HealWeather_ScoreDown2 - if_equal AI_WEATHER_RAIN, AI_CV_HealWeather_ScoreDown2 - if_equal AI_WEATHER_SANDSTORM, AI_CV_HealWeather_ScoreDown2 - goto AI_CV_Heal - -AI_CV_HealWeather_ScoreDown2:: - score -2 - -AI_CV_Heal:: - if_hp_equal AI_USER, 100, AI_CV_Heal3 - if_target_faster AI_CV_Heal4 - score -8 - goto AI_CV_Heal_End - -@ Never reached -AI_CV_Heal2: - if_hp_less_than AI_USER, 50, AI_CV_Heal5 - if_hp_more_than AI_USER, 80, AI_CV_Heal3 - if_random_less_than 70, AI_CV_Heal5 - -AI_CV_Heal3:: - score -3 - goto AI_CV_Heal_End - -AI_CV_Heal4:: - if_hp_less_than AI_USER, 70, AI_CV_Heal5 - if_random_less_than 30, AI_CV_Heal5 - score -3 - goto AI_CV_Heal_End - -AI_CV_Heal5:: - if_doesnt_have_move_with_effect AI_TARGET, EFFECT_SNATCH, AI_CV_Heal6 - if_random_less_than 100, AI_CV_Heal_End - -AI_CV_Heal6:: - if_random_less_than 20, AI_CV_Heal_End - score +2 - -AI_CV_Heal_End:: - end - -AI_CV_Toxic:: - if_user_has_no_attacking_moves AI_CV_Toxic3 - if_hp_more_than AI_USER, 50, AI_CV_Toxic2 - if_random_less_than 50, AI_CV_Toxic2 - score -3 - -AI_CV_Toxic2:: - if_hp_more_than AI_TARGET, 50, AI_CV_Toxic3 - if_random_less_than 50, AI_CV_Toxic3 - score -3 - -AI_CV_Toxic3:: - if_has_move_with_effect AI_USER, EFFECT_SPECIAL_DEFENSE_UP, AI_CV_Toxic4 - if_has_move_with_effect AI_USER, EFFECT_PROTECT, AI_CV_Toxic4 - goto AI_CV_Toxic_End - -AI_CV_Toxic4:: - if_random_less_than 60, AI_CV_Toxic_End - score +2 - -AI_CV_Toxic_End:: - end - -AI_CV_LightScreen:: - if_hp_less_than AI_USER, 50, AI_CV_LightScreen_ScoreDown2 - get_target_type1 - if_in_bytes AI_CV_LightScreen_SpecialTypeList, AI_CV_LightScreen_End - get_target_type2 - if_in_bytes AI_CV_LightScreen_SpecialTypeList, AI_CV_LightScreen_End - if_random_less_than 50, AI_CV_LightScreen_End - -AI_CV_LightScreen_ScoreDown2:: - score -2 - -AI_CV_LightScreen_End:: - end - -AI_CV_LightScreen_SpecialTypeList:: - .byte TYPE_FIRE - .byte TYPE_WATER - .byte TYPE_GRASS - .byte TYPE_ELECTRIC - .byte TYPE_PSYCHIC - .byte TYPE_ICE - .byte TYPE_DRAGON - .byte TYPE_DARK - .byte TYPE_FAIRY - .byte -1 - -AI_CV_Rest:: - if_target_faster AI_CV_Rest4 - if_hp_not_equal AI_USER, 100, AI_CV_Rest2 - score -8 - goto AI_CV_Rest_End - -AI_CV_Rest2:: - if_hp_less_than AI_USER, 40, AI_CV_Rest6 - if_hp_more_than AI_USER, 50, AI_CV_Rest3 - if_random_less_than 70, AI_CV_Rest6 - -AI_CV_Rest3:: - score -3 - goto AI_CV_Rest_End - -AI_CV_Rest4:: - if_hp_less_than AI_USER, 60, AI_CV_Rest6 - if_hp_more_than AI_USER, 70, AI_CV_Rest5 - if_random_less_than 50, AI_CV_Rest6 - -AI_CV_Rest5:: - score -3 - goto AI_CV_Rest_End - -AI_CV_Rest6:: - if_doesnt_have_move_with_effect AI_TARGET, EFFECT_SNATCH, AI_CV_Rest7 - if_random_less_than 50, AI_CV_Rest_End - -AI_CV_Rest7:: - if_random_less_than 10, AI_CV_Rest_End - score +3 - -AI_CV_Rest_End:: - end - -AI_CV_OneHitKO:: - end - -AI_CV_SuperFang:: - if_hp_more_than AI_TARGET, 50, AI_CV_SuperFang_End - score -1 - -AI_CV_SuperFang_End:: - end - -AI_CV_Trap:: - if_status AI_TARGET, STATUS1_TOXIC_POISON, AI_CV_Trap2 - if_status2 AI_TARGET, STATUS2_CURSED, AI_CV_Trap2 - if_status3 AI_TARGET, STATUS3_PERISH_SONG, AI_CV_Trap2 - if_status2 AI_TARGET, STATUS2_INFATUATION, AI_CV_Trap2 - goto AI_CV_Trap_End - -AI_CV_Trap2:: - if_random_less_than 128, AI_CV_Trap_End - score +1 - -AI_CV_Trap_End:: - end - -AI_CV_HighCrit:: - if_type_effectiveness AI_EFFECTIVENESS_x0_25, AI_CV_HighCrit_End - if_type_effectiveness AI_EFFECTIVENESS_x0_5, AI_CV_HighCrit_End - if_type_effectiveness AI_EFFECTIVENESS_x2, AI_CV_HighCrit2 - if_type_effectiveness AI_EFFECTIVENESS_x4, AI_CV_HighCrit2 - if_random_less_than 128, AI_CV_HighCrit_End - -AI_CV_HighCrit2:: - if_random_less_than 128, AI_CV_HighCrit_End - score +1 - -AI_CV_HighCrit_End:: - end - -@ Improvement in Emerald -@AI_CV_Swagger: -@ if_has_move AI_USER, MOVE_PSYCH_UP, AI_CV_SwaggerHasPsychUp - -AI_CV_Flatter:: - if_random_less_than 128, AI_CV_Confuse - score +1 - -AI_CV_Confuse:: - if_hp_more_than AI_TARGET, 70, AI_CV_Confuse_End - if_random_less_than 128, AI_CV_Confuse2 - score -1 - -AI_CV_Confuse2:: - if_hp_more_than AI_TARGET, 50, AI_CV_Confuse_End - score -1 - if_hp_more_than AI_TARGET, 30, AI_CV_Confuse_End - score -1 - -AI_CV_Confuse_End:: - end - -@ Improvement in Emerald -@AI_CV_SwaggerHasPsychUp: -@ if_stat_level_more_than AI_TARGET, STAT_ATK, 3, AI_CV_SwaggerHasPsychUp_Minus5 -@ score +3 -@ get_turn_count -@ if_not_equal 0, AI_CV_SwaggerHasPsychUp_End -@ score +2 -@ goto AI_CV_SwaggerHasPsychUp_End -@ -@AI_CV_SwaggerHasPsychUp_Minus5: -@ score -5 -@ -@AI_CV_SwaggerHasPsychUp_End: -@ end - -AI_CV_Reflect:: - if_hp_less_than AI_USER, 50, AI_CV_Reflect_ScoreDown2 - get_target_type1 - if_in_bytes AI_CV_Reflect_PhysicalTypeList, AI_CV_Reflect_End - get_target_type2 - if_in_bytes AI_CV_Reflect_PhysicalTypeList, AI_CV_Reflect_End - if_random_less_than 50, AI_CV_Reflect_End - -AI_CV_Reflect_ScoreDown2:: - score -2 - -AI_CV_Reflect_End:: - end - -AI_CV_Reflect_PhysicalTypeList:: - .byte TYPE_NORMAL - .byte TYPE_FIGHTING - .byte TYPE_FLYING - .byte TYPE_POISON - .byte TYPE_GROUND - .byte TYPE_ROCK - .byte TYPE_BUG - .byte TYPE_GHOST - .byte TYPE_STEEL - .byte -1 - -AI_CV_Poison:: - if_hp_less_than AI_USER, 50, AI_CV_Poison_ScoreDown1 - if_hp_more_than AI_TARGET, 50, AI_CV_Poison_End - -AI_CV_Poison_ScoreDown1:: - score -1 - -AI_CV_Poison_End:: - end - -AI_CV_Paralyze:: - if_target_faster AI_CV_Paralyze2 - if_hp_more_than AI_USER, 70, AI_CV_Paralyze_End - score -1 - goto AI_CV_Paralyze_End - -AI_CV_Paralyze2:: - if_random_less_than 20, AI_CV_Paralyze_End - score +3 - -AI_CV_Paralyze_End:: - end - -AI_CV_VitalThrow:: - if_target_faster AI_CV_VitalThrow_End - if_hp_more_than AI_USER, 60, AI_CV_VitalThrow_End - if_hp_less_than AI_USER, 40, AI_CV_VitalThrow2 - if_random_less_than 180, AI_CV_VitalThrow_End - -AI_CV_VitalThrow2:: - if_random_less_than 50, AI_CV_VitalThrow_End - score -1 - -AI_CV_VitalThrow_End:: - end - -AI_CV_Substitute:: - if_hp_more_than AI_USER, 90, AI_CV_Substitute4 - if_hp_more_than AI_USER, 70, AI_CV_Substitute3 - if_hp_more_than AI_USER, 50, AI_CV_Substitute2 - if_random_less_than 100, AI_CV_Substitute2 - score -1 - -AI_CV_Substitute2:: - if_random_less_than 100, AI_CV_Substitute3 - score -1 - -AI_CV_Substitute3:: - if_random_less_than 100, AI_CV_Substitute4 - score -1 - -AI_CV_Substitute4:: - if_target_faster AI_CV_Substitute_End - get_last_used_move AI_TARGET - get_move_effect_from_result - if_equal EFFECT_SLEEP, AI_CV_Substitute5 - if_equal EFFECT_TOXIC, AI_CV_Substitute5 - if_equal EFFECT_POISON, AI_CV_Substitute5 - if_equal EFFECT_PARALYZE, AI_CV_Substitute5 - if_equal EFFECT_WILL_O_WISP, AI_CV_Substitute5 - if_equal EFFECT_CONFUSE, AI_CV_Substitute6 - if_equal EFFECT_LEECH_SEED, AI_CV_Substitute7 - goto AI_CV_Substitute_End - -AI_CV_Substitute5:: - if_not_status AI_TARGET, STATUS1_ANY, AI_CV_Substitute8 - goto AI_CV_Substitute_End - -AI_CV_Substitute6:: - if_not_status2 AI_TARGET, STATUS2_CONFUSION, AI_CV_Substitute8 - goto AI_CV_Substitute_End - -AI_CV_Substitute7:: - if_status3 AI_TARGET, STATUS3_LEECHSEED, AI_CV_Substitute_End - -AI_CV_Substitute8:: - if_random_less_than 100, AI_CV_Substitute_End - score +1 - -AI_CV_Substitute_End:: - end - -AI_CV_Recharge:: - if_type_effectiveness AI_EFFECTIVENESS_x0_25, AI_CV_Recharge_ScoreDown1 - if_type_effectiveness AI_EFFECTIVENESS_x0_5, AI_CV_Recharge_ScoreDown1 - if_target_faster AI_CV_Recharge2 - if_hp_more_than AI_USER, 40, AI_CV_Recharge_ScoreDown1 - goto AI_CV_Recharge_End - -AI_CV_Recharge2:: - if_hp_less_than AI_USER, 60, AI_CV_Recharge_End - -AI_CV_Recharge_ScoreDown1:: - score -1 - -AI_CV_Recharge_End:: - end - -AI_CV_Disable:: - if_target_faster AI_CV_Disable_End - get_last_used_move AI_TARGET - get_move_power_from_result - if_equal 0, AI_CV_Disable2 - score +1 - goto AI_CV_Disable_End - -AI_CV_Disable2:: - if_random_less_than 100, AI_CV_Disable_End - score -1 - -AI_CV_Disable_End:: - end - -AI_CV_Counter:: - if_status AI_TARGET, STATUS1_SLEEP, AI_CV_Counter_ScoreDown1 - if_status2 AI_TARGET, STATUS2_INFATUATION, AI_CV_Counter_ScoreDown1 - if_status2 AI_TARGET, STATUS2_CONFUSION, AI_CV_Counter_ScoreDown1 - if_hp_more_than AI_USER, 30, AI_CV_Counter2 - if_random_less_than 10, AI_CV_Counter2 - score -1 - -AI_CV_Counter2:: - if_hp_more_than AI_USER, 50, AI_CV_Counter3 - if_random_less_than 100, AI_CV_Counter3 - score -1 - -AI_CV_Counter3:: -@ if_has_move AI_USER, MOVE_MIRROR_COAT, AI_CV_Counter7 @ Improvement in Emerald - get_last_used_move AI_TARGET - get_move_power_from_result - if_equal 0, AI_CV_Counter5 - if_target_not_taunted AI_CV_Counter4 - if_random_less_than 100, AI_CV_Counter4 - score +1 - -AI_CV_Counter4:: - get_last_used_move AI_TARGET - get_move_type_from_result - if_not_in_bytes AI_CV_Counter_PhysicalTypeList, AI_CV_Counter_ScoreDown1 - if_random_less_than 100, AI_CV_Counter_End - score +1 - goto AI_CV_Counter_End - -AI_CV_Counter5:: - if_target_not_taunted AI_CV_Counter6 - if_random_less_than 100, AI_CV_Counter6 - score +1 - -AI_CV_Counter6:: - get_target_type1 - if_in_bytes AI_CV_Counter_PhysicalTypeList, AI_CV_Counter_End - get_target_type2 - if_in_bytes AI_CV_Counter_PhysicalTypeList, AI_CV_Counter_End - if_random_less_than 50, AI_CV_Counter_End - -@ Improvement in Emerald -@AI_CV_Counter7: -@ if_random_less_than 100, AI_CV_Counter8 -@ score +4 -@ -@AI_CV_Counter8: -@ end - -AI_CV_Counter_ScoreDown1:: - score -1 - -AI_CV_Counter_End:: - end - -AI_CV_Counter_PhysicalTypeList:: - .byte TYPE_NORMAL - .byte TYPE_FIGHTING - .byte TYPE_FLYING - .byte TYPE_POISON - .byte TYPE_GROUND - .byte TYPE_ROCK - .byte TYPE_BUG - .byte TYPE_GHOST - .byte TYPE_STEEL - .byte -1 - -AI_CV_Encore:: - if_any_move_disabled AI_TARGET, AI_CV_Encore2 - if_target_faster AI_CV_Encore_ScoreDown2 - get_last_used_move AI_TARGET - get_move_effect_from_result - if_not_in_bytes AI_CV_Encore_EncouragedMovesToEncore, AI_CV_Encore_ScoreDown2 - -AI_CV_Encore2:: - if_random_less_than 30, AI_CV_Encore_End - score +3 - goto AI_CV_Encore_End - -AI_CV_Encore_ScoreDown2:: - score -2 - -AI_CV_Encore_End:: - end - -AI_CV_Encore_EncouragedMovesToEncore:: - .2byte EFFECT_DREAM_EATER - .2byte EFFECT_ATTACK_UP - .2byte EFFECT_DEFENSE_UP - .2byte EFFECT_SPEED_UP - .2byte EFFECT_SPECIAL_ATTACK_UP - .2byte EFFECT_HAZE - .2byte EFFECT_ROAR - .2byte EFFECT_CONVERSION - .2byte EFFECT_TOXIC - .2byte EFFECT_LIGHT_SCREEN - .2byte EFFECT_REST - .2byte EFFECT_SUPER_FANG - .2byte EFFECT_SPECIAL_DEFENSE_UP_2 - .2byte EFFECT_CONFUSE - .2byte EFFECT_POISON - .2byte EFFECT_PARALYZE - .2byte EFFECT_LEECH_SEED - .2byte EFFECT_SPLASH - .2byte EFFECT_ATTACK_UP_2 - .2byte EFFECT_ENCORE - .2byte EFFECT_CONVERSION_2 - .2byte EFFECT_LOCK_ON - .2byte EFFECT_HEAL_BELL - .2byte EFFECT_MEAN_LOOK - .2byte EFFECT_NIGHTMARE - .2byte EFFECT_PROTECT - .2byte EFFECT_SKILL_SWAP - .2byte EFFECT_FORESIGHT - .2byte EFFECT_PERISH_SONG - .2byte EFFECT_SANDSTORM - .2byte EFFECT_ENDURE - .2byte EFFECT_SWAGGER - .2byte EFFECT_ATTRACT - .2byte EFFECT_SAFEGUARD - .2byte EFFECT_RAIN_DANCE - .2byte EFFECT_SUNNY_DAY - .2byte EFFECT_BELLY_DRUM - .2byte EFFECT_PSYCH_UP - .2byte EFFECT_FUTURE_SIGHT - .2byte EFFECT_FAKE_OUT - .2byte EFFECT_STOCKPILE - .2byte EFFECT_SPIT_UP - .2byte EFFECT_SWALLOW - .2byte EFFECT_HAIL - .2byte EFFECT_TORMENT - .2byte EFFECT_WILL_O_WISP - .2byte EFFECT_FOLLOW_ME - .2byte EFFECT_CHARGE - .2byte EFFECT_TRICK - .2byte EFFECT_ROLE_PLAY - .2byte EFFECT_INGRAIN - .2byte EFFECT_RECYCLE - .2byte EFFECT_KNOCK_OFF - .2byte EFFECT_SKILL_SWAP - .2byte EFFECT_IMPRISON - .2byte EFFECT_REFRESH - .2byte EFFECT_GRUDGE - .2byte EFFECT_TEETER_DANCE - .2byte EFFECT_MUD_SPORT - .2byte EFFECT_WATER_SPORT - .2byte EFFECT_DRAGON_DANCE - .2byte EFFECT_CAMOUFLAGE - .2byte -1 - -AI_CV_PainSplit:: - if_hp_less_than AI_TARGET, 80, AI_CV_PainSplit_ScoreDown1 - if_target_faster AI_CV_PainSplit2 - if_hp_more_than AI_USER, 40, AI_CV_PainSplit_ScoreDown1 - score +1 - goto AI_CV_PainSplit_End - -AI_CV_PainSplit2:: - if_hp_more_than AI_USER, 60, AI_CV_PainSplit_ScoreDown1 - score +1 - goto AI_CV_PainSplit_End - -AI_CV_PainSplit_ScoreDown1:: - score -1 - -AI_CV_PainSplit_End:: - end - -AI_CV_Snore:: - score +2 - end - -AI_CV_LockOn:: - if_random_less_than 128, AI_CV_LockOn_End - score +2 - -AI_CV_LockOn_End:: - end - -AI_CV_SleepTalk:: -@ if_status AI_USER, STATUS1_SLEEP, Score_Plus10 @ Improvement in Emerald - score +2 @ Change to -5 - end - -AI_CV_DestinyBond:: - score -1 - if_target_faster AI_CV_DestinyBond_End - if_hp_more_than AI_USER, 70, AI_CV_DestinyBond_End - if_random_less_than 128, AI_CV_DestinyBond2 - score +1 - -AI_CV_DestinyBond2:: - if_hp_more_than AI_USER, 50, AI_CV_DestinyBond_End - if_random_less_than 128, AI_CV_DestinyBond3 - score +1 - -AI_CV_DestinyBond3:: - if_hp_more_than AI_USER, 30, AI_CV_DestinyBond_End - if_random_less_than 100, AI_CV_DestinyBond_End - score +2 - -AI_CV_DestinyBond_End:: - end - -AI_CV_Flail:: - if_target_faster AI_CV_Flail2 - if_hp_more_than AI_USER, 33, AI_CV_Flail_ScoreDown1 - if_hp_more_than AI_USER, 20, AI_CV_Flail_End - if_hp_less_than AI_USER, 8, AI_CV_Flail_ScoreUp1 - goto AI_CV_Flail3 - -AI_CV_Flail2:: - if_hp_more_than AI_USER, 60, AI_CV_Flail_ScoreDown1 - if_hp_more_than AI_USER, 40, AI_CV_Flail_End - goto AI_CV_Flail3 - -AI_CV_Flail_ScoreUp1:: - score +1 - -AI_CV_Flail3:: - if_random_less_than 100, AI_CV_Flail_End - score +1 - goto AI_CV_Flail_End - -AI_CV_Flail_ScoreDown1:: - score -1 - -AI_CV_Flail_End:: - end - -AI_CV_HealBell:: - if_status AI_TARGET, STATUS1_ANY, AI_CV_HealBell_End - if_status_in_party AI_TARGET, STATUS1_ANY, AI_CV_HealBell_End - score -5 - -AI_CV_HealBell_End:: - end - -AI_CV_Thief:: - get_hold_effect AI_TARGET - if_not_in_bytes AI_CV_Thief_EncourageItemsToSteal, AI_CV_Thief_ScoreDown2 - if_random_less_than 50, AI_CV_Thief_End - score +1 - goto AI_CV_Thief_End - -AI_CV_Thief_ScoreDown2:: - score -2 - -AI_CV_Thief_End:: - end - -AI_CV_Thief_EncourageItemsToSteal:: - .byte HOLD_EFFECT_CURE_SLP - .byte HOLD_EFFECT_CURE_STATUS - .byte HOLD_EFFECT_RESTORE_HP - .byte HOLD_EFFECT_EVASION_UP - .byte HOLD_EFFECT_LEFTOVERS - .byte HOLD_EFFECT_LIGHT_BALL - .byte HOLD_EFFECT_THICK_CLUB - .byte -1 - -AI_CV_Curse:: - get_user_type1 - if_equal TYPE_GHOST, AI_CV_Curse4 - get_user_type2 - if_equal TYPE_GHOST, AI_CV_Curse4 - if_stat_level_more_than AI_USER, STAT_DEF, 9, AI_CV_Curse_End - if_random_less_than 128, AI_CV_Curse2 - score +1 - -AI_CV_Curse2:: - if_stat_level_more_than AI_USER, STAT_DEF, 7, AI_CV_Curse_End - if_random_less_than 128, AI_CV_Curse3 - score +1 - -AI_CV_Curse3:: - if_stat_level_more_than AI_USER, STAT_DEF, 6, AI_CV_Curse_End - if_random_less_than 128, AI_CV_Curse_End - score +1 - goto AI_CV_Curse_End - -AI_CV_Curse4:: - if_hp_more_than AI_USER, 80, AI_CV_Curse_End - score -1 - -AI_CV_Curse_End:: - end - -AI_CV_Protect:: - get_protect_count AI_USER - if_more_than 1, AI_CV_Protect_ScoreDown2 - if_status AI_USER, STATUS1_TOXIC_POISON, AI_CV_Protect3 - if_status2 AI_USER, STATUS2_CURSED, AI_CV_Protect3 - if_status3 AI_USER, STATUS3_PERISH_SONG, AI_CV_Protect3 - if_status2 AI_USER, STATUS2_INFATUATION, AI_CV_Protect3 - if_status3 AI_USER, STATUS3_LEECHSEED, AI_CV_Protect3 - if_status3 AI_USER, STATUS3_YAWN, AI_CV_Protect3 - if_has_move_with_effect AI_TARGET, EFFECT_RESTORE_HP, AI_CV_Protect3 - if_has_move_with_effect AI_TARGET, EFFECT_DEFENSE_CURL, AI_CV_Protect3 - if_status AI_TARGET, STATUS1_TOXIC_POISON, AI_CV_Protect_ScoreUp2 - if_status2 AI_TARGET, STATUS2_CURSED, AI_CV_Protect_ScoreUp2 - if_status3 AI_TARGET, STATUS3_PERISH_SONG, AI_CV_Protect_ScoreUp2 - if_status2 AI_TARGET, STATUS2_INFATUATION, AI_CV_Protect_ScoreUp2 - if_status3 AI_TARGET, STATUS3_LEECHSEED, AI_CV_Protect_ScoreUp2 - if_status3 AI_TARGET, STATUS3_YAWN, AI_CV_Protect_ScoreUp2 - get_last_used_move AI_TARGET - get_move_effect_from_result - if_not_equal EFFECT_LOCK_ON, AI_CV_Protect_ScoreUp2 - goto AI_CV_Protect2 - -AI_CV_Protect_ScoreUp2:: - score +2 - -AI_CV_Protect2:: -@ if_random_less_than 128, AI_CV_Protect4 @ Improvement in Emerald -@ score -1 - -AI_CV_Protect4:: - get_protect_count AI_USER - if_equal 0, AI_CV_Protect_End - score -1 - if_random_less_than 128, AI_CV_Protect_End - score -1 - goto AI_CV_Protect_End - -AI_CV_Protect3:: - get_last_used_move AI_TARGET - get_move_effect_from_result - if_not_equal EFFECT_LOCK_ON, AI_CV_Protect_End - -AI_CV_Protect_ScoreDown2:: - score -2 - -AI_CV_Protect_End:: - end - -AI_CV_Foresight:: - get_user_type1 - if_equal TYPE_GHOST, AI_CV_Foresight2 - get_user_type2 - if_equal TYPE_GHOST, AI_CV_Foresight2 - if_stat_level_more_than AI_USER, STAT_EVASION, 8, AI_CV_Foresight3 - score -2 - goto AI_CV_Foresight_End - -AI_CV_Foresight2:: - if_random_less_than 80, AI_CV_Foresight_End - -AI_CV_Foresight3:: - if_random_less_than 80, AI_CV_Foresight_End - score +2 - -AI_CV_Foresight_End:: - end - -AI_CV_Endure:: - if_hp_less_than AI_USER, 4, AI_CV_Endure2 - if_hp_less_than AI_USER, 35, AI_CV_Endure3 - -AI_CV_Endure2:: - score -1 - goto AI_CV_Endure_End - -AI_CV_Endure3:: - if_random_less_than 70, AI_CV_Endure_End - score +1 - -AI_CV_Endure_End:: - end - -AI_CV_BatonPass:: - if_stat_level_more_than AI_USER, STAT_ATK, 8, AI_CV_BatonPass2 - if_stat_level_more_than AI_USER, STAT_DEF, 8, AI_CV_BatonPass2 - if_stat_level_more_than AI_USER, STAT_SPATK, 8, AI_CV_BatonPass2 - if_stat_level_more_than AI_USER, STAT_SPDEF, 8, AI_CV_BatonPass2 - if_stat_level_more_than AI_USER, STAT_EVASION, 8, AI_CV_BatonPass2 - goto AI_CV_BatonPass5 - -AI_CV_BatonPass2:: - if_target_faster AI_CV_BatonPass3 - if_hp_more_than AI_USER, 60, AI_CV_BatonPass_End - goto AI_CV_BatonPass4 - -AI_CV_BatonPass3:: - if_hp_more_than AI_USER, 70, AI_CV_BatonPass_End - -AI_CV_BatonPass4:: - if_random_less_than 80, AI_CV_BatonPass_End - score +2 - goto AI_CV_BatonPass_End - -AI_CV_BatonPass5:: - if_stat_level_more_than AI_USER, STAT_ATK, 7, AI_CV_BatonPass7 - if_stat_level_more_than AI_USER, STAT_DEF, 7, AI_CV_BatonPass7 - if_stat_level_more_than AI_USER, STAT_SPATK, 7, AI_CV_BatonPass7 - if_stat_level_more_than AI_USER, STAT_SPDEF, 7, AI_CV_BatonPass7 - if_stat_level_more_than AI_USER, STAT_EVASION, 7, AI_CV_BatonPass7 - goto AI_CV_BatonPass_ScoreDown2 - -AI_CV_BatonPass7:: - if_target_faster AI_CV_BatonPass8 - if_hp_more_than AI_USER, 60, AI_CV_BatonPass_ScoreDown2 - goto AI_CV_BatonPass_End - -AI_CV_BatonPass8:: - if_hp_less_than AI_USER, 70, AI_CV_BatonPass_End - -AI_CV_BatonPass_ScoreDown2:: - score -2 - -AI_CV_BatonPass_End:: - end - -AI_CV_Pursuit:: - is_first_turn_for AI_USER - if_not_equal 0, AI_CV_Pursuit_End - get_target_type1 - if_equal TYPE_GHOST, AI_CV_Pursuit2 - get_target_type1 - if_equal TYPE_PSYCHIC, AI_CV_Pursuit2 - get_target_type2 - if_equal TYPE_GHOST, AI_CV_Pursuit2 - get_target_type2 - if_equal TYPE_PSYCHIC, AI_CV_Pursuit2 - goto AI_CV_Pursuit_End - -AI_CV_Pursuit2:: - if_random_less_than 128, AI_CV_Pursuit_End - score +1 - -AI_CV_Pursuit_End:: - end - -AI_CV_RainDance:: - if_user_faster AI_CV_RainDance2 - get_ability AI_USER - if_equal ABILITY_SWIFT_SWIM, AI_CV_RainDance3 - -AI_CV_RainDance2:: - if_hp_less_than AI_USER, 40, AI_CV_RainDance_ScoreDown1 - get_weather - if_equal AI_WEATHER_HAIL, AI_CV_RainDance3 - if_equal AI_WEATHER_SUN, AI_CV_RainDance3 - if_equal AI_WEATHER_SANDSTORM, AI_CV_RainDance3 - get_ability AI_USER - if_equal ABILITY_RAIN_DISH, AI_CV_RainDance3 - goto AI_CV_RainDance_End - -AI_CV_RainDance3:: - score +1 - goto AI_CV_RainDance_End - -AI_CV_RainDance_ScoreDown1:: - score -1 - -AI_CV_RainDance_End:: - end - -AI_CV_SunnyDay:: - if_hp_less_than AI_USER, 40, AI_CV_SunnyDay_ScoreDown1 - get_weather - if_equal AI_WEATHER_HAIL, AI_CV_SunnyDay2 - if_equal AI_WEATHER_RAIN, AI_CV_SunnyDay2 - if_equal AI_WEATHER_SANDSTORM, AI_CV_SunnyDay2 - goto AI_CV_SunnyDay_End - -AI_CV_SunnyDay2:: - score +1 - goto AI_CV_SunnyDay_End - -AI_CV_SunnyDay_ScoreDown1:: - score -1 - -AI_CV_SunnyDay_End:: - end - -AI_CV_BellyDrum:: - if_hp_less_than AI_USER, 90, AI_CV_BellyDrum_ScoreDown2 - goto AI_CV_BellyDrum_End - -AI_CV_BellyDrum_ScoreDown2:: - score -2 - -AI_CV_BellyDrum_End:: - end - -AI_CV_PsychUp:: - if_stat_level_more_than AI_TARGET, STAT_ATK, 8, AI_CV_PsychUp2 - if_stat_level_more_than AI_TARGET, STAT_DEF, 8, AI_CV_PsychUp2 - if_stat_level_more_than AI_TARGET, STAT_SPATK, 8, AI_CV_PsychUp2 - if_stat_level_more_than AI_TARGET, STAT_SPDEF, 8, AI_CV_PsychUp2 - if_stat_level_more_than AI_TARGET, STAT_EVASION, 8, AI_CV_PsychUp2 - goto AI_CV_PsychUp_ScoreDown2 - -AI_CV_PsychUp2:: - if_stat_level_less_than AI_USER, STAT_ATK, 7, AI_CV_PsychUp3 - if_stat_level_less_than AI_USER, STAT_DEF, 7, AI_CV_PsychUp3 - if_stat_level_less_than AI_USER, STAT_SPATK, 7, AI_CV_PsychUp3 - if_stat_level_less_than AI_USER, STAT_SPDEF, 7, AI_CV_PsychUp3 - if_stat_level_less_than AI_USER, STAT_EVASION, 7, AI_CV_PsychUp_ScoreUp1 - if_random_less_than 50, AI_CV_PsychUp_End - goto AI_CV_PsychUp_ScoreDown2 - -AI_CV_PsychUp_ScoreUp1:: - score +1 - -AI_CV_PsychUp3:: - if_random_less_than 128, AI_CV_PsychUp_End @ Remove this line - score +1 -@ end @ Improvement in Emerald - -AI_CV_PsychUp_ScoreDown2:: - score -2 - -AI_CV_PsychUp_End:: - end - -AI_CV_MirrorCoat:: - if_status AI_TARGET, STATUS1_SLEEP, AI_CV_MirrorCoat_ScoreDown1 - if_status2 AI_TARGET, STATUS2_INFATUATION, AI_CV_MirrorCoat_ScoreDown1 - if_status2 AI_TARGET, STATUS2_CONFUSION, AI_CV_MirrorCoat_ScoreDown1 - if_hp_more_than AI_USER, 30, AI_CV_MirrorCoat2 - if_random_less_than 10, AI_CV_MirrorCoat2 - score -1 - -AI_CV_MirrorCoat2:: - if_hp_more_than AI_USER, 50, AI_CV_MirrorCoat3 - if_random_less_than 100, AI_CV_MirrorCoat3 - score -1 - -AI_CV_MirrorCoat3:: -@ if_has_move AI_USER, MOVE_COUNTER, AI_CV_MirrorCoat_ScoreUp4 @ Improvement in Emerald - get_last_used_move AI_TARGET - get_move_power_from_result - if_equal 0, AI_CV_MirrorCoat5 - if_target_not_taunted AI_CV_MirrorCoat4 - if_random_less_than 100, AI_CV_MirrorCoat4 - score +1 - -AI_CV_MirrorCoat4:: - get_last_used_move AI_TARGET - get_move_type_from_result - if_not_in_bytes AI_CV_MirrorCoat_SpecialTypeList, AI_CV_MirrorCoat_ScoreDown1 - if_random_less_than 100, AI_CV_MirrorCoat_End - score +1 - goto AI_CV_MirrorCoat_End - -AI_CV_MirrorCoat5:: - if_target_not_taunted AI_CV_MirrorCoat6 - if_random_less_than 100, AI_CV_MirrorCoat6 - score +1 - -AI_CV_MirrorCoat6:: - get_target_type1 - if_in_bytes AI_CV_MirrorCoat_SpecialTypeList, AI_CV_MirrorCoat_End - get_target_type2 - if_in_bytes AI_CV_MirrorCoat_SpecialTypeList, AI_CV_MirrorCoat_End - if_random_less_than 50, AI_CV_MirrorCoat_End - -@ Improvement in Emerald -@AI_CV_MirrorCoat_ScoreUp4: -@ if_random_less_than 100, AI_CV_MirrorCoat_ScoreUp4_End -@ score +4 -@ -@AI_CV_MirrorCoat_ScoreUp4_End: -@ end - -AI_CV_MirrorCoat_ScoreDown1:: - score -1 - -AI_CV_MirrorCoat_End:: - end - -AI_CV_MirrorCoat_SpecialTypeList:: - .byte TYPE_FIRE - .byte TYPE_WATER - .byte TYPE_GRASS - .byte TYPE_ELECTRIC - .byte TYPE_PSYCHIC - .byte TYPE_ICE - .byte TYPE_DRAGON - .byte TYPE_DARK - .byte TYPE_FAIRY - .byte -1 - -AI_CV_ChargeUpMove:: - if_type_effectiveness AI_EFFECTIVENESS_x0_25, AI_CV_ChargeUpMove_ScoreDown2 - if_type_effectiveness AI_EFFECTIVENESS_x0_5, AI_CV_ChargeUpMove_ScoreDown2 - if_has_move_with_effect AI_TARGET, EFFECT_PROTECT, AI_CV_ChargeUpMove_ScoreDown2 - if_hp_more_than AI_USER, 38, AI_CV_ChargeUpMove_End - score -1 - goto AI_CV_ChargeUpMove_End - -AI_CV_ChargeUpMove_ScoreDown2:: - score -2 - -AI_CV_ChargeUpMove_End:: - end - -AI_CV_SemiInvulnerable:: - if_doesnt_have_move_with_effect AI_TARGET, EFFECT_PROTECT, AI_CV_SemiInvulnerable2 - score -1 - goto AI_CV_SemiInvulnerable_End - -@ BUG: The scripts for checking type-resistance to weather for semi-invulnerable moves are swapped -@ The result is that the AI is encouraged to stall while taking damage from weather -@ To fix, swap _CheckSandstormTypes/_CheckIceType in the below script -AI_CV_SemiInvulnerable2:: - if_status AI_TARGET, STATUS1_TOXIC_POISON, AI_CV_SemiInvulnerable_TryEncourage - if_status2 AI_TARGET, STATUS2_CURSED, AI_CV_SemiInvulnerable_TryEncourage - if_status3 AI_TARGET, STATUS3_LEECHSEED, AI_CV_SemiInvulnerable_TryEncourage - get_weather - if_equal AI_WEATHER_HAIL, AI_CV_SemiInvulnerable_CheckSandstormTypes - if_equal AI_WEATHER_SANDSTORM, AI_CV_SemiInvulnerable_CheckIceType - goto AI_CV_SemiInvulnerable5 - -AI_CV_SemiInvulnerable_CheckSandstormTypes:: - get_user_type1 - if_in_bytes AI_CV_SandstormResistantTypes, AI_CV_SemiInvulnerable_TryEncourage - get_user_type2 - if_in_bytes AI_CV_SandstormResistantTypes, AI_CV_SemiInvulnerable_TryEncourage - goto AI_CV_SemiInvulnerable5 - -AI_CV_SemiInvulnerable_CheckIceType:: - get_user_type1 - if_equal TYPE_ICE, AI_CV_SemiInvulnerable_TryEncourage - get_user_type2 - if_equal TYPE_ICE, AI_CV_SemiInvulnerable_TryEncourage - -AI_CV_SemiInvulnerable5:: - if_target_faster AI_CV_SemiInvulnerable_End - get_last_used_move AI_TARGET - get_move_effect_from_result - if_not_equal EFFECT_LOCK_ON, AI_CV_SemiInvulnerable_TryEncourage - goto AI_CV_SemiInvulnerable_End - -AI_CV_SemiInvulnerable_TryEncourage:: - if_random_less_than 80, AI_CV_SemiInvulnerable_End - score +1 - -AI_CV_SemiInvulnerable_End:: - end - -AI_CV_SandstormResistantTypes:: - .byte TYPE_GROUND - .byte TYPE_ROCK - .byte TYPE_STEEL - .byte -1 - -AI_CV_FakeOut:: - score +2 - end - -AI_CV_SpitUp:: - get_stockpile_count AI_USER - if_less_than 2, AI_CV_SpitUp_End - if_random_less_than 80, AI_CV_SpitUp_End - score +2 - -AI_CV_SpitUp_End:: - end - -AI_CV_Hail:: - if_hp_less_than AI_USER, 40, AI_CV_Hail_ScoreDown1 - get_weather - if_equal AI_WEATHER_SUN, AI_CV_Hail2 - if_equal AI_WEATHER_RAIN, AI_CV_Hail2 - if_equal AI_WEATHER_SANDSTORM, AI_CV_Hail2 - goto AI_CV_Hail_End - -AI_CV_Hail2:: - score +1 - goto AI_CV_Hail_End - -AI_CV_Hail_ScoreDown1:: - score -1 - -AI_CV_Hail_End:: - end - -@ BUG: Facade score is increased if the target is statused, but should be if the user is. Replace AI_TARGET with AI_USER -AI_CV_Facade:: - if_not_status AI_TARGET, STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON, AI_CV_Facade_End - score +1 - -AI_CV_Facade_End:: - end - -AI_CV_FocusPunch:: - if_type_effectiveness AI_EFFECTIVENESS_x0_25, AI_CV_FocusPunch2 - if_type_effectiveness AI_EFFECTIVENESS_x0_5, AI_CV_FocusPunch2 - if_status AI_TARGET, STATUS1_SLEEP, AI_CV_FocusPunch_ScoreUp1 - if_status2 AI_TARGET, STATUS2_INFATUATION, AI_CV_FocusPunch3 - if_status2 AI_TARGET, STATUS2_CONFUSION, AI_CV_FocusPunch3 - is_first_turn_for AI_USER - if_not_equal 0, AI_CV_FocusPunch_End - if_random_less_than 100, AI_CV_FocusPunch_End - score +1 - goto AI_CV_FocusPunch_End - -AI_CV_FocusPunch2:: - score -1 - goto AI_CV_FocusPunch_End - -AI_CV_FocusPunch3:: - if_random_less_than 100, AI_CV_FocusPunch_End - -AI_CV_FocusPunch_ScoreUp1:: - score +1 - -AI_CV_FocusPunch_End:: - end - -AI_CV_SmellingSalt:: - if_status AI_TARGET, STATUS1_PARALYSIS, AI_CV_SmellingSalt_ScoreUp1 - goto AI_CV_SmellingSalt_End - -AI_CV_SmellingSalt_ScoreUp1:: - score +1 - -AI_CV_SmellingSalt_End:: - end - -AI_CV_Trick:: - get_hold_effect AI_USER - if_in_bytes AI_CV_Trick_ChoiceEffects, AI_CV_Trick3 - if_in_bytes AI_CV_Trick_EffectsToEncourage, AI_CV_Trick4 - -AI_CV_Trick2:: - score -3 - goto AI_CV_Trick_End - -AI_CV_Trick3:: - get_hold_effect AI_TARGET - if_in_bytes AI_CV_Trick_ChoiceEffects, AI_CV_Trick2 - score +5 - goto AI_CV_Trick_End - -AI_CV_Trick4:: - get_hold_effect AI_TARGET - if_in_bytes AI_CV_Trick_EffectsToEncourage, AI_CV_Trick2 - if_random_less_than 50, AI_CV_Trick_End - score +2 - -AI_CV_Trick_End:: - end - -AI_CV_Trick_EffectsToEncourage:: - .byte HOLD_EFFECT_CONFUSE_SPICY - .byte HOLD_EFFECT_CONFUSE_DRY - .byte HOLD_EFFECT_CONFUSE_SWEET - .byte HOLD_EFFECT_CONFUSE_BITTER - .byte HOLD_EFFECT_CONFUSE_SOUR - .byte HOLD_EFFECT_MACHO_BRACE - .byte HOLD_EFFECT_CHOICE_BAND - .byte -1 - -AI_CV_Trick_ChoiceEffects:: - .byte HOLD_EFFECT_CHOICE_BAND - .byte -1 - -AI_CV_ChangeSelfAbility:: - get_ability AI_USER - if_in_bytes AI_CV_ChangeSelfAbility_AbilitiesToEncourage, AI_CV_ChangeSelfAbility2 - get_ability AI_TARGET - if_in_bytes AI_CV_ChangeSelfAbility_AbilitiesToEncourage, AI_CV_ChangeSelfAbility3 - -AI_CV_ChangeSelfAbility2:: - score -1 - goto AI_CV_ChangeSelfAbility_End - -AI_CV_ChangeSelfAbility3:: - if_random_less_than 50, AI_CV_ChangeSelfAbility_End - score +2 - -AI_CV_ChangeSelfAbility_End:: - end - -AI_CV_ChangeSelfAbility_AbilitiesToEncourage:: - .2byte ABILITY_SPEED_BOOST - .2byte ABILITY_BATTLE_ARMOR - .2byte ABILITY_SAND_VEIL - .2byte ABILITY_STATIC - .2byte ABILITY_FLASH_FIRE - .2byte ABILITY_WONDER_GUARD - .2byte ABILITY_EFFECT_SPORE - .2byte ABILITY_SWIFT_SWIM - .2byte ABILITY_HUGE_POWER - .2byte ABILITY_RAIN_DISH - .2byte ABILITY_CUTE_CHARM - .2byte ABILITY_SHED_SKIN - .2byte ABILITY_MARVEL_SCALE - .2byte ABILITY_PURE_POWER - .2byte ABILITY_CHLOROPHYLL - .2byte ABILITY_SHIELD_DUST - .2byte -1 - -AI_CV_Superpower:: - if_type_effectiveness AI_EFFECTIVENESS_x0_25, AI_CV_Superpower_ScoreDown1 - if_type_effectiveness AI_EFFECTIVENESS_x0_5, AI_CV_Superpower_ScoreDown1 - if_stat_level_less_than AI_USER, STAT_ATK, 6, AI_CV_Superpower_ScoreDown1 - if_target_faster AI_CV_Superpower2 - if_hp_more_than AI_USER, 40, AI_CV_Superpower_ScoreDown1 - goto AI_CV_Superpower_End - -AI_CV_Superpower2:: - if_hp_less_than AI_USER, 60, AI_CV_Superpower_End - -AI_CV_Superpower_ScoreDown1:: - score -1 - -AI_CV_Superpower_End:: - end - -AI_CV_MagicCoat:: - if_hp_more_than AI_TARGET, 30, AI_CV_MagicCoat2 - if_random_less_than 100, AI_CV_MagicCoat2 - score -1 - -AI_CV_MagicCoat2:: - is_first_turn_for AI_USER - if_equal 0, AI_CV_MagicCoat4 - if_random_less_than 150, AI_CV_MagicCoat_End - score +1 - goto AI_CV_MagicCoat_End - if_random_less_than 50, AI_CV_MagicCoat_End - -AI_CV_MagicCoat3:: -@ if_random_less_than 50, AI_CV_MagicCoat_End @ Improvement in Emerald - -AI_CV_MagicCoat4:: - if_random_less_than 30, AI_CV_MagicCoat_End - score -1 - -AI_CV_MagicCoat_End:: - end - -AI_CV_Recycle:: - get_used_held_item AI_USER - if_not_in_bytes AI_CV_Recycle_ItemsToEncourage, AI_CV_Recycle_ScoreDown2 - if_random_less_than 50, AI_CV_Recycle_End - score +1 - goto AI_CV_Recycle_End - -AI_CV_Recycle_ScoreDown2:: - score -2 - -AI_CV_Recycle_End:: - end - -AI_CV_Recycle_ItemsToEncourage:: - .2byte ITEM_CHESTO_BERRY - .2byte ITEM_LUM_BERRY - .2byte ITEM_STARF_BERRY - .2byte -1 - -AI_CV_Revenge:: - if_status AI_TARGET, STATUS1_SLEEP, AI_CV_Revenge_ScoreDown2 - if_status2 AI_TARGET, STATUS2_INFATUATION, AI_CV_Revenge_ScoreDown2 - if_status2 AI_TARGET, STATUS2_CONFUSION, AI_CV_Revenge_ScoreDown2 - if_random_less_than 180, AI_CV_Revenge_ScoreDown2 - score +2 - goto AI_CV_Revenge_End - -AI_CV_Revenge_ScoreDown2:: - score -2 - -AI_CV_Revenge_End:: - end - -AI_CV_BrickBreak:: - if_side_affecting AI_TARGET, SIDE_STATUS_REFLECT, AI_CV_BrickBreak_ScoreUp1 - goto AI_CV_BrickBreak_End - -AI_CV_BrickBreak_ScoreUp1:: - score +1 - -AI_CV_BrickBreak_End:: - end - -AI_CV_KnockOff:: - if_hp_less_than AI_TARGET, 30, AI_CV_KnockOff_End - is_first_turn_for AI_USER - if_more_than 0, AI_CV_KnockOff_End - if_random_less_than 180, AI_CV_KnockOff_End - score +1 - -AI_CV_KnockOff_End:: - end - -AI_CV_Endeavor:: - if_hp_less_than AI_TARGET, 70, AI_CV_Endeavor_ScoreDown1 - if_target_faster AI_CV_Endeavor2 - if_hp_more_than AI_USER, 40, AI_CV_Endeavor_ScoreDown1 - score +1 - goto AI_CV_Endeavor_End - -AI_CV_Endeavor2:: - if_hp_more_than AI_USER, 50, AI_CV_Endeavor_ScoreDown1 - score +1 - goto AI_CV_Endeavor_End - -AI_CV_Endeavor_ScoreDown1:: - score -1 - -AI_CV_Endeavor_End:: - end - -AI_CV_Eruption:: - if_type_effectiveness AI_EFFECTIVENESS_x0_25, AI_CV_Eruption_ScoreDown1 - if_type_effectiveness AI_EFFECTIVENESS_x0_5, AI_CV_Eruption_ScoreDown1 - if_target_faster AI_CV_Eruption2 - if_hp_more_than AI_TARGET, 50, AI_CV_Eruption_End - goto AI_CV_Eruption_ScoreDown1 - -AI_CV_Eruption2:: - if_hp_more_than AI_TARGET, 70, AI_CV_Eruption_End - -AI_CV_Eruption_ScoreDown1:: - score -1 - -AI_CV_Eruption_End:: - end - -AI_CV_Imprison:: - is_first_turn_for AI_USER - if_more_than 0, AI_CV_Imprison_End - if_random_less_than 100, AI_CV_Imprison_End - score +2 - -AI_CV_Imprison_End:: - end - -AI_CV_Refresh:: - if_hp_less_than AI_TARGET, 50, AI_CV_Refresh_ScoreDown1 - goto AI_CV_Refresh_End - -AI_CV_Refresh_ScoreDown1:: - score -1 - -AI_CV_Refresh_End:: - end - -AI_CV_Snatch:: - is_first_turn_for AI_USER - if_equal 1, AI_CV_Snatch3 - if_random_less_than 30, AI_CV_Snatch_End - if_target_faster AI_CV_Snatch2 - if_hp_not_equal AI_USER, 100, AI_CV_Snatch5 - if_hp_less_than AI_TARGET, 70, AI_CV_Snatch5 - if_random_less_than 60, AI_CV_Snatch_End - goto AI_CV_Snatch5 - -AI_CV_Snatch2:: - if_hp_more_than AI_TARGET, 25, AI_CV_Snatch5 - if_has_move_with_effect AI_TARGET, EFFECT_RESTORE_HP, AI_CV_Snatch3 - if_has_move_with_effect AI_TARGET, EFFECT_DEFENSE_CURL, AI_CV_Snatch3 - goto AI_CV_Snatch4 - -AI_CV_Snatch3:: - if_random_less_than 150, AI_CV_Snatch_End - score +2 - goto AI_CV_Snatch_End - -AI_CV_Snatch4:: - if_random_less_than 230, AI_CV_Snatch5 - score +1 - goto AI_CV_Snatch_End - -AI_CV_Snatch5:: - if_random_less_than 30, AI_CV_Snatch_End - score -2 - -AI_CV_Snatch_End:: - end - -AI_CV_MudSport:: - if_hp_less_than AI_USER, 50, AI_CV_MudSport_ScoreDown1 - get_target_type1 - if_equal TYPE_ELECTRIC, AI_CV_MudSport2 - get_target_type2 - if_equal TYPE_ELECTRIC, AI_CV_MudSport2 - goto AI_CV_MudSport_ScoreDown1 - -AI_CV_MudSport2:: - score +1 - goto AI_CV_MudSport_End - -AI_CV_MudSport_ScoreDown1:: - score -1 - -AI_CV_MudSport_End:: - end - -AI_CV_Overheat:: - if_type_effectiveness AI_EFFECTIVENESS_x0_25, AI_CV_Overheat_ScoreDown1 - if_type_effectiveness AI_EFFECTIVENESS_x0_5, AI_CV_Overheat_ScoreDown1 - if_target_faster AI_CV_Overheat2 - if_hp_more_than AI_USER, 60, AI_CV_Overheat_End - goto AI_CV_Overheat_ScoreDown1 - -AI_CV_Overheat2:: - if_hp_more_than AI_USER, 80, AI_CV_Overheat_End - -AI_CV_Overheat_ScoreDown1:: - score -1 - -AI_CV_Overheat_End:: - end - -AI_CV_WaterSport:: - if_hp_less_than AI_USER, 50, AI_CV_WaterSport_ScoreDown1 - get_target_type1 - if_equal TYPE_FIRE, AI_CV_WaterSport2 - get_target_type2 - if_equal TYPE_FIRE, AI_CV_WaterSport2 - goto AI_CV_WaterSport_ScoreDown1 - -AI_CV_WaterSport2:: - score +1 - goto AI_CV_WaterSport_End - -AI_CV_WaterSport_ScoreDown1:: - score -1 - -AI_CV_WaterSport_End:: - end - -AI_CV_DragonDance:: - if_target_faster AI_CV_DragonDance2 - if_hp_more_than AI_USER, 50, AI_CV_DragonDance_End - if_random_less_than 70, AI_CV_DragonDance_End - score -1 - goto AI_CV_DragonDance_End - -AI_CV_DragonDance2:: - if_random_less_than 128, AI_CV_DragonDance_End - score +1 - -AI_CV_DragonDance_End:: - end - -AI_TryToFaint:: - if_can_faint AI_TryToFaint_TryToEncourageQuickAttack - get_how_powerful_move_is - if_equal MOVE_NOT_MOST_POWERFUL, Score_Minus1 -@ if_type_effectiveness AI_EFFECTIVENESS_x4, AI_TryToFaint_DoubleSuperEffective @ Improvement in Emerald - end - -@ Improvement in Emerald -@AI_TryToFaint_DoubleSuperEffective: -@ if_random_less_than 80, AI_TryToFaint_End -@ score +2 -@ end - -AI_TryToFaint_TryToEncourageQuickAttack:: - if_effect EFFECT_EXPLOSION, AI_TryToFaint_End - if_not_effect EFFECT_QUICK_ATTACK, AI_TryToFaint_ScoreUp4 - score +2 - -AI_TryToFaint_ScoreUp4:: - score +4 - -AI_TryToFaint_End:: - end - -AI_SetupFirstTurn:: - get_turn_count - if_not_equal 0, AI_SetupFirstTurn_End - get_considered_move_effect - if_not_in_bytes AI_SetupFirstTurn_SetupEffectsToEncourage, AI_SetupFirstTurn_End - if_random_less_than 80, AI_SetupFirstTurn_End - score +2 - -AI_SetupFirstTurn_End:: - end - -AI_SetupFirstTurn_SetupEffectsToEncourage:: - .2byte EFFECT_ATTACK_UP - .2byte EFFECT_DEFENSE_UP - .2byte EFFECT_SPEED_UP - .2byte EFFECT_SPECIAL_ATTACK_UP - .2byte EFFECT_SPECIAL_DEFENSE_UP - .2byte EFFECT_ACCURACY_UP - .2byte EFFECT_EVASION_UP - .2byte EFFECT_ATTACK_DOWN - .2byte EFFECT_DEFENSE_DOWN - .2byte EFFECT_SPEED_DOWN - .2byte EFFECT_SPECIAL_ATTACK_DOWN - .2byte EFFECT_SPECIAL_DEFENSE_DOWN - .2byte EFFECT_ACCURACY_DOWN - .2byte EFFECT_EVASION_DOWN - .2byte EFFECT_CONVERSION - .2byte EFFECT_LIGHT_SCREEN - .2byte EFFECT_SPECIAL_DEFENSE_UP_2 - .2byte EFFECT_FOCUS_ENERGY - .2byte EFFECT_CONFUSE - .2byte EFFECT_ATTACK_UP_2 - .2byte EFFECT_DEFENSE_UP_2 - .2byte EFFECT_SPEED_UP_2 - .2byte EFFECT_SPECIAL_ATTACK_UP_2 - .2byte EFFECT_SPECIAL_DEFENSE_UP_2 - .2byte EFFECT_ACCURACY_UP_2 - .2byte EFFECT_EVASION_UP_2 - .2byte EFFECT_ATTACK_DOWN_2 - .2byte EFFECT_DEFENSE_DOWN_2 - .2byte EFFECT_SPEED_DOWN_2 - .2byte EFFECT_SPECIAL_ATTACK_DOWN_2 - .2byte EFFECT_SPECIAL_DEFENSE_DOWN_2 - .2byte EFFECT_ACCURACY_DOWN_2 - .2byte EFFECT_EVASION_DOWN_2 - .2byte EFFECT_REFLECT - .2byte EFFECT_POISON - .2byte EFFECT_PARALYZE - .2byte EFFECT_SUBSTITUTE - .2byte EFFECT_LEECH_SEED - .2byte EFFECT_MINIMIZE - .2byte EFFECT_CURSE - .2byte EFFECT_SWAGGER - .2byte EFFECT_CAMOUFLAGE - .2byte EFFECT_YAWN - .2byte EFFECT_DEFENSE_CURL - .2byte EFFECT_TORMENT - .2byte EFFECT_FLATTER - .2byte EFFECT_WILL_O_WISP - .2byte EFFECT_INGRAIN - .2byte EFFECT_IMPRISON - .2byte EFFECT_TEETER_DANCE - .2byte EFFECT_TICKLE - .2byte EFFECT_COSMIC_POWER - .2byte EFFECT_BULK_UP - .2byte EFFECT_CALM_MIND - .2byte EFFECT_CAMOUFLAGE - .2byte -1 - -AI_PreferStrongestMove:: - get_how_powerful_move_is - if_not_equal MOVE_POWER_DISCOURAGED, AI_PreferStrongestMove_End - if_random_less_than 100, AI_PreferStrongestMove_End - score +2 - -AI_PreferStrongestMove_End:: - end - -AI_Risky:: - get_considered_move_effect - if_not_in_bytes AI_Risky_EffectsToEncourage, AI_Risky_End - if_random_less_than 128, AI_Risky_End - score +2 - -AI_Risky_End:: - end - -AI_Risky_EffectsToEncourage:: - .2byte EFFECT_SLEEP - .2byte EFFECT_EXPLOSION - .2byte EFFECT_MIRROR_MOVE - .2byte EFFECT_OHKO - .2byte EFFECT_HIGH_CRITICAL - .2byte EFFECT_CONFUSE - .2byte EFFECT_METRONOME - .2byte EFFECT_PSYWAVE - .2byte EFFECT_COUNTER - .2byte EFFECT_DESTINY_BOND - .2byte EFFECT_SWAGGER - .2byte EFFECT_ATTRACT - .2byte EFFECT_PRESENT - .2byte EFFECT_ALL_STATS_UP_HIT - .2byte EFFECT_BELLY_DRUM - .2byte EFFECT_MIRROR_COAT - .2byte EFFECT_FOCUS_PUNCH - .2byte EFFECT_REVENGE - .2byte EFFECT_TEETER_DANCE - .2byte -1 - -AI_PreferBatonPass:: - count_alive_pokemon AI_USER - if_equal 0, AI_PreferBatonPass_End - get_how_powerful_move_is - if_not_equal MOVE_POWER_DISCOURAGED, AI_PreferBatonPass_End - if_has_move_with_effect AI_USER, EFFECT_BATON_PASS, AI_PreferBatonPass_GoForBatonPass - if_random_less_than 80, AI_Risky_End - -@ Improvement in Emerald (several below) -AI_PreferBatonPass_GoForBatonPass:: -@ if_move MOVE_SWORDS_DANCE, AI_PreferBatonPass2 -@ if_move MOVE_DRAGON_DANCE, AI_PreferBatonPass2 -@ if_move MOVE_CALM_MIND, AI_PreferBatonPass2 -@ if_effect EFFECT_PROTECT, AI_PreferBatonPass3 -@ if_move MOVE_BATON_PASS, AI_PreferBatonPass_EncourageIfHighStats - if_random_less_than 20, AI_Risky_End - score +3 - -@AI_PreferBatonPass2: -@ get_turn_count -@ if_equal 0, Score_Plus5 -@ if_hp_less_than AI_USER, 60, Score_Minus10 -@ goto Score_Plus1 -@ -@AI_PreferBatonPass3:: -@ get_last_used_move AI_USER -@ if_in_hwords AI_PreferBatonPass_ProtectMoves, Score_Minus2 -@ score +2 -@ end -@ -@AI_PreferBatonPass_ProtectMoves: -@ .2byte MOVE_PROTECT -@ .2byte MOVE_DETECT -@ .2byte -1 -@ -@AI_PreferBatonPass_EncourageIfHighStats: -@ get_turn_count -@ if_equal 0, Score_Minus2 -@ if_stat_level_more_than AI_USER, STAT_ATK, 8, Score_Plus3 -@ if_stat_level_more_than AI_USER, STAT_ATK, 7, Score_Plus2 -@ if_stat_level_more_than AI_USER, STAT_ATK, 6, Score_Plus1 -@ if_stat_level_more_than AI_USER, STAT_SPATK, 8, Score_Plus3 -@ if_stat_level_more_than AI_USER, STAT_SPATK, 7, Score_Plus2 -@ if_stat_level_more_than AI_USER, STAT_SPATK, 6, Score_Plus1 -@ end - -AI_PreferBatonPass_End:: - end - -@ Empty. Expanded in Emerald -AI_DoubleBattle:: - end - -AI_HPAware:: - if_hp_more_than AI_USER, 70, AI_HPAware_UserHasHighHP - if_hp_more_than AI_USER, 30, AI_HPAware_UserHasMediumHP - get_considered_move_effect - if_in_bytes AI_HPAware_DiscouragedEffectsWhenLowHP, AI_HPAware_TryToDiscourage - goto AI_HPAware_ConsiderTarget - -AI_HPAware_UserHasHighHP:: - get_considered_move_effect - if_in_bytes AI_HPAware_DiscouragedEffectsWhenHighHP, AI_HPAware_TryToDiscourage - goto AI_HPAware_ConsiderTarget - -AI_HPAware_UserHasMediumHP:: - get_considered_move_effect - if_in_bytes AI_HPAware_DiscouragedEffectsWhenMediumHP, AI_HPAware_TryToDiscourage - goto AI_HPAware_ConsiderTarget - -AI_HPAware_TryToDiscourage:: - if_random_less_than 50, AI_HPAware_ConsiderTarget - score -2 - -AI_HPAware_ConsiderTarget:: - if_hp_more_than AI_TARGET, 70, AI_HPAware_TargetHasHighHP - if_hp_more_than AI_TARGET, 30, AI_HPAware_TargetHasMediumHP - get_considered_move_effect - if_in_bytes AI_HPAware_DiscouragedEffectsWhenTargetLowHP, AI_HPAware_TargetTryToDiscourage - goto AI_HPAware_End - -AI_HPAware_TargetHasHighHP:: - get_considered_move_effect - if_in_bytes AI_HPAware_DiscouragedEffectsWhenTargetHighHP, AI_HPAware_TargetTryToDiscourage - goto AI_HPAware_End - -AI_HPAware_TargetHasMediumHP:: - get_considered_move_effect - if_in_bytes AI_HPAware_DiscouragedEffectsWhenTargetMediumHP, AI_HPAware_TargetTryToDiscourage - goto AI_HPAware_End - -AI_HPAware_TargetTryToDiscourage:: - if_random_less_than 50, AI_HPAware_End - score -2 - -AI_HPAware_End:: - end - -AI_HPAware_DiscouragedEffectsWhenHighHP:: - .2byte EFFECT_EXPLOSION - .2byte EFFECT_RESTORE_HP - .2byte EFFECT_REST - .2byte EFFECT_DESTINY_BOND - .2byte EFFECT_FLAIL - .2byte EFFECT_ENDURE - .2byte EFFECT_MORNING_SUN - .2byte EFFECT_SYNTHESIS - .2byte EFFECT_MOONLIGHT - .2byte EFFECT_SOFTBOILED - .2byte EFFECT_MEMENTO - .2byte EFFECT_GRUDGE - .2byte EFFECT_OVERHEAT - .2byte -1 - -AI_HPAware_DiscouragedEffectsWhenMediumHP:: - .2byte EFFECT_EXPLOSION - .2byte EFFECT_ATTACK_UP - .2byte EFFECT_DEFENSE_UP - .2byte EFFECT_SPEED_UP - .2byte EFFECT_SPECIAL_ATTACK_UP - .2byte EFFECT_SPECIAL_DEFENSE_UP - .2byte EFFECT_ACCURACY_UP - .2byte EFFECT_EVASION_UP - .2byte EFFECT_ATTACK_DOWN - .2byte EFFECT_DEFENSE_DOWN - .2byte EFFECT_SPEED_DOWN - .2byte EFFECT_SPECIAL_ATTACK_DOWN - .2byte EFFECT_SPECIAL_DEFENSE_DOWN - .2byte EFFECT_ACCURACY_DOWN - .2byte EFFECT_EVASION_DOWN - .2byte EFFECT_BIDE - .2byte EFFECT_CONVERSION - .2byte EFFECT_LIGHT_SCREEN - .2byte EFFECT_MIST - .2byte EFFECT_FOCUS_ENERGY - .2byte EFFECT_ATTACK_UP_2 - .2byte EFFECT_DEFENSE_UP_2 - .2byte EFFECT_SPEED_UP_2 - .2byte EFFECT_SPECIAL_ATTACK_UP_2 - .2byte EFFECT_SPECIAL_DEFENSE_UP_2 - .2byte EFFECT_ACCURACY_UP_2 - .2byte EFFECT_EVASION_UP_2 - .2byte EFFECT_ATTACK_DOWN_2 - .2byte EFFECT_DEFENSE_DOWN_2 - .2byte EFFECT_SPEED_DOWN_2 - .2byte EFFECT_SPECIAL_ATTACK_DOWN_2 - .2byte EFFECT_SPECIAL_DEFENSE_DOWN_2 - .2byte EFFECT_ACCURACY_DOWN_2 - .2byte EFFECT_EVASION_DOWN_2 - .2byte EFFECT_CONVERSION_2 - .2byte EFFECT_SAFEGUARD - .2byte EFFECT_BELLY_DRUM - .2byte EFFECT_TICKLE - .2byte EFFECT_COSMIC_POWER - .2byte EFFECT_BULK_UP - .2byte EFFECT_CALM_MIND - .2byte EFFECT_DRAGON_DANCE - .2byte -1 - -AI_HPAware_DiscouragedEffectsWhenLowHP:: - .2byte EFFECT_ATTACK_UP - .2byte EFFECT_DEFENSE_UP - .2byte EFFECT_SPEED_UP - .2byte EFFECT_SPECIAL_ATTACK_UP - .2byte EFFECT_SPECIAL_DEFENSE_UP - .2byte EFFECT_ACCURACY_UP - .2byte EFFECT_EVASION_UP - .2byte EFFECT_ATTACK_DOWN - .2byte EFFECT_DEFENSE_DOWN - .2byte EFFECT_SPEED_DOWN - .2byte EFFECT_SPECIAL_ATTACK_DOWN - .2byte EFFECT_SPECIAL_DEFENSE_DOWN - .2byte EFFECT_ACCURACY_DOWN - .2byte EFFECT_EVASION_DOWN - .2byte EFFECT_BIDE - .2byte EFFECT_CONVERSION - .2byte EFFECT_LIGHT_SCREEN - .2byte EFFECT_MIST - .2byte EFFECT_FOCUS_ENERGY - .2byte EFFECT_ATTACK_UP_2 - .2byte EFFECT_DEFENSE_UP_2 - .2byte EFFECT_SPEED_UP_2 - .2byte EFFECT_SPECIAL_ATTACK_UP_2 - .2byte EFFECT_SPECIAL_DEFENSE_UP_2 - .2byte EFFECT_ACCURACY_UP_2 - .2byte EFFECT_EVASION_UP_2 - .2byte EFFECT_ATTACK_DOWN_2 - .2byte EFFECT_DEFENSE_DOWN_2 - .2byte EFFECT_SPEED_DOWN_2 - .2byte EFFECT_SPECIAL_ATTACK_DOWN_2 - .2byte EFFECT_SPECIAL_DEFENSE_DOWN_2 - .2byte EFFECT_ACCURACY_DOWN_2 - .2byte EFFECT_EVASION_DOWN_2 - .2byte EFFECT_RAGE - .2byte EFFECT_CONVERSION_2 - .2byte EFFECT_LOCK_ON - .2byte EFFECT_SAFEGUARD - .2byte EFFECT_BELLY_DRUM - .2byte EFFECT_PSYCH_UP - .2byte EFFECT_MIRROR_COAT - .2byte EFFECT_SOLAR_BEAM - .2byte EFFECT_ERUPTION - .2byte EFFECT_TICKLE - .2byte EFFECT_COSMIC_POWER - .2byte EFFECT_BULK_UP - .2byte EFFECT_CALM_MIND - .2byte EFFECT_DRAGON_DANCE - .2byte -1 - -AI_HPAware_DiscouragedEffectsWhenTargetHighHP:: - .2byte -1 - -AI_HPAware_DiscouragedEffectsWhenTargetMediumHP:: - .2byte EFFECT_ATTACK_UP - .2byte EFFECT_DEFENSE_UP - .2byte EFFECT_SPEED_UP - .2byte EFFECT_SPECIAL_ATTACK_UP - .2byte EFFECT_SPECIAL_DEFENSE_UP - .2byte EFFECT_ACCURACY_UP - .2byte EFFECT_EVASION_UP - .2byte EFFECT_ATTACK_DOWN - .2byte EFFECT_DEFENSE_DOWN - .2byte EFFECT_SPEED_DOWN - .2byte EFFECT_SPECIAL_ATTACK_DOWN - .2byte EFFECT_SPECIAL_DEFENSE_DOWN - .2byte EFFECT_ACCURACY_DOWN - .2byte EFFECT_EVASION_DOWN - .2byte EFFECT_MIST - .2byte EFFECT_FOCUS_ENERGY - .2byte EFFECT_ATTACK_UP_2 - .2byte EFFECT_DEFENSE_UP_2 - .2byte EFFECT_SPEED_UP_2 - .2byte EFFECT_SPECIAL_ATTACK_UP_2 - .2byte EFFECT_SPECIAL_DEFENSE_UP_2 - .2byte EFFECT_ACCURACY_UP_2 - .2byte EFFECT_EVASION_UP_2 - .2byte EFFECT_ATTACK_DOWN_2 - .2byte EFFECT_DEFENSE_DOWN_2 - .2byte EFFECT_SPEED_DOWN_2 - .2byte EFFECT_SPECIAL_ATTACK_DOWN_2 - .2byte EFFECT_SPECIAL_DEFENSE_DOWN_2 - .2byte EFFECT_ACCURACY_DOWN_2 - .2byte EFFECT_EVASION_DOWN_2 - .2byte EFFECT_POISON - .2byte EFFECT_PAIN_SPLIT - .2byte EFFECT_PERISH_SONG - .2byte EFFECT_SAFEGUARD - .2byte EFFECT_TICKLE - .2byte EFFECT_COSMIC_POWER - .2byte EFFECT_BULK_UP - .2byte EFFECT_CALM_MIND - .2byte EFFECT_DRAGON_DANCE - .2byte -1 - -AI_HPAware_DiscouragedEffectsWhenTargetLowHP:: - .2byte EFFECT_SLEEP - .2byte EFFECT_EXPLOSION - .2byte EFFECT_ATTACK_UP - .2byte EFFECT_DEFENSE_UP - .2byte EFFECT_SPEED_UP - .2byte EFFECT_SPECIAL_ATTACK_UP - .2byte EFFECT_SPECIAL_DEFENSE_UP - .2byte EFFECT_ACCURACY_UP - .2byte EFFECT_EVASION_UP - .2byte EFFECT_ATTACK_DOWN - .2byte EFFECT_DEFENSE_DOWN - .2byte EFFECT_SPEED_DOWN - .2byte EFFECT_SPECIAL_ATTACK_DOWN - .2byte EFFECT_SPECIAL_DEFENSE_DOWN - .2byte EFFECT_ACCURACY_DOWN - .2byte EFFECT_EVASION_DOWN - .2byte EFFECT_BIDE - .2byte EFFECT_CONVERSION - .2byte EFFECT_TOXIC - .2byte EFFECT_LIGHT_SCREEN - .2byte EFFECT_OHKO - .2byte EFFECT_SUPER_FANG @ Maybe supposed to be EFFECT_RAZOR_WIND - .2byte EFFECT_SUPER_FANG - .2byte EFFECT_MIST - .2byte EFFECT_FOCUS_ENERGY - .2byte EFFECT_CONFUSE - .2byte EFFECT_ATTACK_UP_2 - .2byte EFFECT_DEFENSE_UP_2 - .2byte EFFECT_SPEED_UP_2 - .2byte EFFECT_SPECIAL_ATTACK_UP_2 - .2byte EFFECT_SPECIAL_DEFENSE_UP_2 - .2byte EFFECT_ACCURACY_UP_2 - .2byte EFFECT_EVASION_UP_2 - .2byte EFFECT_ATTACK_DOWN_2 - .2byte EFFECT_DEFENSE_DOWN_2 - .2byte EFFECT_SPEED_DOWN_2 - .2byte EFFECT_SPECIAL_ATTACK_DOWN_2 - .2byte EFFECT_SPECIAL_DEFENSE_DOWN_2 - .2byte EFFECT_ACCURACY_DOWN_2 - .2byte EFFECT_EVASION_DOWN_2 - .2byte EFFECT_POISON - .2byte EFFECT_PARALYZE - .2byte EFFECT_PAIN_SPLIT - .2byte EFFECT_CONVERSION_2 - .2byte EFFECT_LOCK_ON - .2byte EFFECT_SPITE - .2byte EFFECT_PERISH_SONG - .2byte EFFECT_SWAGGER - .2byte EFFECT_FURY_CUTTER - .2byte EFFECT_ATTRACT - .2byte EFFECT_SAFEGUARD - .2byte EFFECT_PSYCH_UP - .2byte EFFECT_MIRROR_COAT - .2byte EFFECT_WILL_O_WISP - .2byte EFFECT_TICKLE - .2byte EFFECT_COSMIC_POWER - .2byte EFFECT_BULK_UP - .2byte EFFECT_CALM_MIND - .2byte EFFECT_DRAGON_DANCE - .2byte -1 - -AI_Unknown:: - if_not_effect EFFECT_SUNNY_DAY, AI_Unknown_End - if_equal 0, AI_Unknown_End - is_first_turn_for AI_USER - if_equal 0, AI_Unknown_End - score +5 - -AI_Unknown_End:: - end - -AI_Roaming:: - if_status2 AI_USER, STATUS2_WRAPPED, AI_Roaming_End - if_status2 AI_USER, STATUS2_ESCAPE_PREVENTION, AI_Roaming_End - get_ability AI_TARGET - if_equal ABILITY_SHADOW_TAG, AI_Roaming_End - get_ability AI_USER - if_equal ABILITY_LEVITATE, AI_Roaming_Flee - get_ability AI_TARGET - if_equal ABILITY_ARENA_TRAP, AI_Roaming_End - -AI_Roaming_Flee:: - flee - -AI_Roaming_End:: - end - -AI_Safari:: - if_random_safari_flee AI_Safari_Flee - watch - -AI_Safari_Flee:: - flee - -@ From Hoenns Poochyena fight (Zigzagoon in Emerald) -AI_FirstBattle:: - if_hp_equal AI_TARGET, 20, AI_FirstBattle_Flee - if_hp_less_than AI_TARGET, 20, AI_FirstBattle_Flee - end - -AI_FirstBattle_Flee:: - flee - -AI_Ret:: - end diff --git a/include/battle.h b/include/battle.h index cbab2f2fc..247be3dd4 100644 --- a/include/battle.h +++ b/include/battle.h @@ -317,29 +317,75 @@ struct WishFutureKnock extern struct WishFutureKnock gWishFutureKnock; +struct AI_SavedBattleMon +{ + u16 ability; + u16 moves[MAX_MON_MOVES]; + u16 heldItem; + u16 species; + u8 types[3]; +}; + +struct AiPartyMon +{ + u16 species; + u16 item; + u16 heldEffect; + u16 ability; + u16 gender; + u16 level; + u16 moves[MAX_MON_MOVES]; + u32 status; + bool8 isFainted; + bool8 wasSentInBattle; + u8 switchInCount; // Counts how many times this Pokemon has been sent out or switched into in a battle. +}; + +struct AIPartyData // Opposing battlers - party mons. +{ + struct AiPartyMon mons[NUM_BATTLE_SIDES][PARTY_SIZE]; // 2 parties(player, opponent). Used to save information on opposing party. + u8 count[NUM_BATTLE_SIDES]; +}; + +struct SwitchinCandidate +{ + struct BattlePokemon battleMon; + bool8 hypotheticalStatus; +}; + +// Ai Data used when deciding which move to use, computed only once before each turn's start. +struct AiLogicData +{ + u16 abilities[MAX_BATTLERS_COUNT]; + u16 items[MAX_BATTLERS_COUNT]; + u16 holdEffects[MAX_BATTLERS_COUNT]; + u8 holdEffectParams[MAX_BATTLERS_COUNT]; + u16 predictedMoves[MAX_BATTLERS_COUNT]; + u8 hpPercents[MAX_BATTLERS_COUNT]; + u16 partnerMove; + u16 speedStats[MAX_BATTLERS_COUNT]; // Speed stats for all battles, calculated only once, same way as damages + s32 simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex + u8 effectiveness[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex + u8 moveAccuracy[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex + u8 moveLimitations[MAX_BATTLERS_COUNT]; + bool8 shouldSwitchMon; // Because all available moves have no/little effect. Each bit per battler. + u8 monToSwitchId[MAX_BATTLERS_COUNT]; // ID of the mon to switch. + bool8 weatherHasEffect; // The same as WEATHER_HAS_EFFECT. Stored here, so it's called only once. + u8 mostSuitableMonId[MAX_BATTLERS_COUNT]; // Stores result of GetMostSuitableMonToSwitchInto, which decides which generic mon the AI would switch into if they decide to switch. This can be overruled by specific mons found in ShouldSwitch; the final resulting mon is stored in AI_monToSwitchIntoId. + struct SwitchinCandidate switchinCandidate; // Struct used for deciding which mon to switch to in battle_ai_switch_items.c +}; + struct AI_ThinkingStruct { u8 aiState; u8 movesetIndex; u16 moveConsidered; - s8 score[4]; + s32 score[MAX_MON_MOVES]; u32 funcResult; - u32 aiFlags; + u32 aiFlags[MAX_BATTLERS_COUNT]; u8 aiAction; u8 aiLogicId; - u8 filler12[6]; - u8 simulatedRNG[4]; -}; - -extern u8 gBattlerTarget; -extern u8 gAbsentBattlerFlags; - -extern struct BattlePokemon gBattleMons[MAX_BATTLERS_COUNT]; - -struct UsedMoves -{ - u16 moves[MAX_BATTLERS_COUNT]; - u16 unknown[MAX_BATTLERS_COUNT]; + struct AI_SavedBattleMon saved[MAX_BATTLERS_COUNT]; }; #define AI_MOVE_HISTORY_COUNT 3 @@ -392,6 +438,11 @@ struct BattleResources extern struct BattleResources *gBattleResources; +#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) +#define AI_DATA ((struct AiLogicData *)(gBattleResources->aiData)) +#define AI_PARTY ((struct AIPartyData *)(gBattleResources->aiParty)) +#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) + struct BattleResults { u8 playerFaintCounter; // 0x0 @@ -659,6 +710,8 @@ struct BattleStruct s32 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier u8 aiMoveOrAction[MAX_BATTLERS_COUNT]; u8 aiChosenTarget[MAX_BATTLERS_COUNT]; + u32 aiDelayTimer; // Counts number of frames AI takes to choose an action. + u32 aiDelayFrames; // Number of frames it took to choose an action. // pokeemerald unknown use u8 field_93; // related to choosing pokemon? probably related to recording }; @@ -942,6 +995,7 @@ extern u8 *gBattleAnimBgTilemapBuffer; extern void (*gBattleMainFunc)(void); extern u8 gMoveSelectionCursor[MAX_BATTLERS_COUNT]; extern u8 gBattlerAttacker; +extern u8 gBattlerTarget; extern u8 gEffectBattler; extern u8 gMultiHitCounter; extern struct BattleScripting gBattleScripting; @@ -999,6 +1053,8 @@ extern u8 gLastUsedBall; extern u16 gLastThrownBall; extern u16 gBallToDisplay; extern struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT]; +extern struct BattlePokemon gBattleMons[MAX_BATTLERS_COUNT]; +extern u8 gAbsentBattlerFlags; static inline u32 GetBattlerPosition(u32 battler) { diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h new file mode 100644 index 000000000..f0527922a --- /dev/null +++ b/include/battle_ai_main.h @@ -0,0 +1,96 @@ +#ifndef GUARD_BATTLE_AI_MAIN_H +#define GUARD_BATTLE_AI_MAIN_H + +#define UNKNOWN_NO_OF_HITS UINT32_MAX + +// return vals for BattleAI_ChooseMoveOrAction +// 0 - 3 are move idx +#define AI_CHOICE_FLEE 4 +#define AI_CHOICE_WATCH 5 +#define AI_CHOICE_SWITCH 7 + +// for AI_WhoStrikesFirst +#define AI_IS_FASTER 1 +#define AI_IS_SLOWER -1 + +// for stat increasing / decreasing scores +#define STAT_CHANGE_ATK 0 +#define STAT_CHANGE_DEF 1 +#define STAT_CHANGE_SPEED 2 +#define STAT_CHANGE_SPATK 3 +#define STAT_CHANGE_SPDEF 4 + +#define STAT_CHANGE_ATK_2 5 +#define STAT_CHANGE_DEF_2 6 +#define STAT_CHANGE_SPEED_2 7 +#define STAT_CHANGE_SPATK_2 8 +#define STAT_CHANGE_SPDEF_2 9 + +#define STAT_CHANGE_ACC 10 +#define STAT_CHANGE_EVASION 11 + +#define BEST_DAMAGE_MOVE 1 // Move with the most amount of hits with the best accuracy/effect +#define POWERFUL_STATUS_MOVE 10 // Moves with this score will be chosen over a move that faints target + +// Temporary scores that are added together to determine a final score at the at of AI_CalcMoveScore +#define WEAK_EFFECT 1 +#define DECENT_EFFECT 2 +#define GOOD_EFFECT 4 +#define BEST_EFFECT 6 + +// AI_CalcMoveScore final score +#define NOT_GOOD_ENOUGH 0 // Not worth using over a damaging move +#define GOOD_MOVE_EFFECTS 2 // Worth using over a damaging move +#define PREFERRED_MOVE_EFFECTS 3 // Worth using over a damagin move and is better then DECENT_EFFECT +#define BEST_MOVE_EFFECTS 4 // Best possible move effects. E.g. stat boosting moves that boost multiply moves + +// AI_TryToFaint +#define FAST_KILL 6 // AI is faster and faints target +#define SLOW_KILL 4 // AI is slower and faints target +#define LAST_CHANCE 2 // AI faints to target. It should try and do damage with a priority move + + +// Logs for debugging AI tests. +#define SET_SCORE(battler, movesetIndex, val) \ + do \ + { \ + AI_THINKING_STRUCT->score[movesetIndex] = val; \ + } while (0) \ + +#define ADJUST_SCORE(val) \ + do \ + { \ + score += val; \ + } while (0) \ + +#define ADJUST_SCORE_PTR(val) \ + do \ + { \ + (*score) += val; \ + } while (0) \ + +#define RETURN_SCORE_PLUS(val) \ +{ \ + ADJUST_SCORE(val); \ + return score; \ +} + +#define RETURN_SCORE_MINUS(val) \ +{ \ + ADJUST_SCORE(-val); \ + return score; \ +} + +u32 ComputeBattleAiScores(u32 battler); +void BattleAI_SetupItems(void); +void BattleAI_SetupFlags(void); +void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler); +u32 BattleAI_ChooseMoveOrAction(void); +void Ai_InitPartyStruct(void); +void Ai_UpdateSwitchInData(u32 battler); +void Ai_UpdateFaintData(u32 battler); +void SetAiLogicDataForTurn(struct AiLogicData *aiData); + +extern u8 sBattler_AI; + +#endif // GUARD_BATTLE_AI_MAIN_H diff --git a/include/battle_ai_script_commands.h b/include/battle_ai_script_commands.h deleted file mode 100644 index eda66484d..000000000 --- a/include/battle_ai_script_commands.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef GUARD_BATTLE_AI_SCRIPT_COMMANDS_H -#define GUARD_BATTLE_AI_SCRIPT_COMMANDS_H - -#include "global.h" - -// return values for BattleAI_ChooseMoveOrAction -// 0 - 3 are move idx -#define AI_CHOICE_FLEE 4 -#define AI_CHOICE_WATCH 5 -#define AI_CHOICE_SWITCH 7 - -void BattleAI_HandleItemUseBeforeAISetup(void); -void BattleAI_SetupAIData(u32 battler); -u8 BattleAI_ChooseMoveOrAction(void); -void ClearBankMoveHistory(u8 bank); -void RecordAbilityBattle(u32 bank, u32 abilityId); -void ClearBankAbilityHistory(u8 bank); -void RecordItemEffectBattle(u32 bank, u32 itemEffect); -void ClearBankItemEffectHistory(u8 bank); -u8 BattleAI_ChooseMoveOrAction(void); - -#endif // GUARD_BATTLE_AI_SCRIPT_COMMANDS_H diff --git a/include/battle_ai_switch_items.h b/include/battle_ai_switch_items.h index 7167377a3..16f646875 100644 --- a/include/battle_ai_switch_items.h +++ b/include/battle_ai_switch_items.h @@ -1,27 +1,9 @@ #ifndef GUARD_BATTLE_AI_SWITCH_ITEMS_H #define GUARD_BATTLE_AI_SWITCH_ITEMS_H -#include "global.h" - -enum { - AI_ITEM_FULL_RESTORE = 1, - AI_ITEM_HEAL_HP, - AI_ITEM_CURE_CONDITION, - AI_ITEM_X_STAT, - AI_ITEM_GUARD_SPECS, - AI_ITEM_NOT_RECOGNIZABLE -}; - -enum { - AI_HEAL_CONFUSION, - AI_HEAL_PARALYSIS, - AI_HEAL_FREEZE, - AI_HEAL_BURN, - AI_HEAL_POISON, - AI_HEAL_SLEEP, -}; - +void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId); void AI_TrySwitchOrUseItem(u32 battler); -u8 GetMostSuitableMonToSwitchInto(u32 battler); +u8 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd); +bool32 ShouldSwitch(u32 battler, bool32 emitResult); #endif // GUARD_BATTLE_AI_SWITCH_ITEMS_H diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h new file mode 100644 index 000000000..ac7aea429 --- /dev/null +++ b/include/battle_ai_util.h @@ -0,0 +1,196 @@ +#ifndef GUARD_BATTLE_AI_UTIL_H +#define GUARD_BATTLE_AI_UTIL_H + +#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE) + +#define AI_STRIKES_FIRST(battlerAi, battlerDef, move)((AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER)) + +bool32 AI_RandLessThan(u32 val); +bool32 IsAiVsAiBattle(void); +bool32 BattlerHasAi(u32 battlerId); +bool32 IsAiBattlerAware(u32 battlerId); +void ClearBattlerMoveHistory(u32 battlerId); +void RecordLastUsedMoveBy(u32 battlerId, u32 move); +void RecordAllMoves(u32 battler); +void RecordKnownMove(u32 battlerId, u32 move); +void RecordAbilityBattle(u32 battlerId, u32 abilityId); +void ClearBattlerAbilityHistory(u32 battlerId); +void RecordItemEffectBattle(u32 battlerId, u32 itemEffect); +void ClearBattlerItemEffectHistory(u32 battlerId); +void SaveBattlerData(u32 battlerId); +void SetBattlerData(u32 battlerId); +void RestoreBattlerData(u32 battlerId); +u32 GetAIChosenMove(u32 battlerId); +u32 GetTotalBaseStat(u32 species); +bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler); +bool32 AtMaxHp(u32 battler); +u32 GetHealthPercentage(u32 battler); +bool32 IsBattlerTrapped(u32 battler, bool32 switching); +s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered); +bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk); +u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk); +u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef); +bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits); +bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod); +s32 AI_DecideKnownAbilityForTurn(u32 battlerId); +u32 AI_DecideHoldEffectForTurn(u32 battlerId); +bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move); +u32 AI_GetWeather(struct AiLogicData *aiData); +bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits); +bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, u32 numHits); +bool32 AI_IsTerrainAffected(u32 battlerId, u32 flags); +bool32 AI_IsBattlerGrounded(u32 battlerId); +bool32 HasDamagingMove(u32 battlerId); +bool32 HasDamagingMoveOfType(u32 battlerId, u32 type); +u32 GetBattlerSecondaryDamage(u32 battlerId); +bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability); +bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability); +bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move); +bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 moveIndex); +u32 GetBattlerSideSpeedAverage(u32 battler); +bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage); +bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent); +bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect); +bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex); +bool32 IsRecycleEncouragedItem(u32 item); +bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item); +bool32 IsStatBoostingBerry(u32 item); +bool32 CanKnockOffItem(u32 battler, u32 item); +bool32 IsAbilityOfRating(u32 ability, s8 rating); +bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability); +bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move); +u32 AI_GetBattlerMoveTargetType(u32 battlerId, u32 move); +bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove); + +// stat stage checks +bool32 AnyStatIsRaised(u32 battlerId); +bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat); +bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat); +bool32 AreBattlersStatsMaxed(u32 battler); +bool32 BattlerHasAnyStatRaised(u32 battlerId); +u32 CountPositiveStatStages(u32 battlerId); +u32 CountNegativeStatStages(u32 battlerId); +bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility); +bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility); +bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility); +bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility); +bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility); +bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility); +bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility); + +// move checks +bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect); +bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category); +s32 AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo); +s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower); +s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower, u32 weather); +bool32 AI_IsDamagedByRecoil(u32 battler); +u32 GetNoOfHitsToKO(u32 dmg, s32 hp); +u32 GetNoOfHitsToKOBattlerDmg(u32 dmg, u32 battlerDef); +u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex); +u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef); +uq4_12_t AI_GetTypeEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef); +u32 AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef); +u16 *GetMovesArray(u32 battler); +bool32 IsConfusionMoveEffect(u32 moveEffect); +bool32 HasMove(u32 battlerId, u32 move); +bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensive); +bool32 HasMoveWithCategory(u32 battler, u32 category); +bool32 HasMoveWithType(u32 battler, u32 type); +bool32 HasMoveEffect(u32 battlerId, u32 moveEffect); +bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument); +bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect); +bool32 HasMoveWithCriticalHitChance(u32 battlerId); +bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception); +bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); +bool32 IsAromaVeilProtectedMove(u32 move); +bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect); +bool32 IsStatLoweringMoveEffect(u32 moveEffect); +bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility); +bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move); +bool32 IsHazardMoveEffect(u32 moveEffect); +bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move); +void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove, s32 *score); +bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect); +bool32 ShouldSetHail(u32 battler, u32 ability, u32 holdEffect); +bool32 ShouldSetSnow(u32 battler, u32 ability, u32 holdEffect); +bool32 ShouldSetRain(u32 battlerAtk, u32 ability, u32 holdEffect); +bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, u32 holdEffect); +bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef); +bool32 IsHealingMove(u32 move); +bool32 HasHealingEffect(u32 battler); +bool32 IsTrappingMove(u32 move); +bool32 HasTrappingMoveEffect(u32 battler); +bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move); +bool32 HasThawingMove(u32 battler); +bool32 IsStatRaisingEffect(u32 effect); +bool32 IsStatLoweringEffect(u32 effect); +bool32 IsAttackBoostMoveEffect(u32 effect); +bool32 IsUngroundingEffect(u32 effect); +bool32 IsSemiInvulnerable(u32 battlerDef, u32 move); +bool32 HasSubstituteIgnoringMove(u32 battler); +bool32 HasHighCritRatioMove(u32 battler); +bool32 HasMagicCoatAffectedMove(u32 battler); +bool32 HasSnatchAffectedMove(u32 battler); + +// status checks +bool32 AI_CanBeBurned(u32 battler, u32 ability); +bool32 AI_CanGetFrostbite(u32 battler, u32 ability); +bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability); +bool32 AI_CanSleep(u32 battler, u32 ability); +bool32 IsBattlerIncapacitated(u32 battler, u32 ability); +bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove); +bool32 ShouldPoisonSelf(u32 battler, u32 ability); +bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove); +bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove); +bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove); +bool32 ShouldBurnSelf(u32 battler, u32 ability); +bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove); +bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove); +bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility); +bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof); +u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move); +bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move); +bool32 IsWakeupTurn(u32 battler); +bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId); + +// partner logic +#define IS_TARGETING_PARTNER(battlerAtk, battlerDef)((battlerAtk) == (battlerDef ^ BIT_FLANK)) +u32 GetAllyChosenMove(u32 battlerId); +bool32 IsValidDoubleBattle(u32 battlerAtk); +bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef); +bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove); +bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove); +bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove); +bool32 IsMoveEffectWeather(u32 move); +bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove); +bool32 PartnerMoveIs(u32 battlerAtkPartner, u32 partnerMove, u32 moveCheck); +bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove); +bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove); +bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move); + +// party logic +struct BattlePokemon *AllocSaveBattleMons(void); +void FreeRestoreBattleMons(struct BattlePokemon *savedBattleMons); +s32 CountUsablePartyMons(u32 battlerId); +bool32 IsPartyFullyHealedExceptBattler(u32 battler); +bool32 PartyHasMoveCategory(u32 battlerId, u32 category); +bool32 SideHasMoveCategory(u32 battlerId, u32 category); + +// score increases +void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score); +void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); +void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); +void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); +void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); +void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); +void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); + +s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, bool8 isPartyMonAttacker); +s32 AI_CheckMoveEffects(u32 battlerAtk, u32 battlerDef, u32 move, s32 score, struct AiLogicData *aiData, u32 predictedMove, bool32 isDoubleBattle); +s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle); +bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef); +bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData); +void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); + +#endif //GUARD_BATTLE_AI_UTIL_H diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 6cd98e8c9..96ae0a6c7 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -53,6 +53,11 @@ bool32 CanBattlerSwitch(u32 battlerId); u8 GetFirstFaintedPartyIndex(u8 battlerId); u16 GetNaturePowerMove(void); bool32 CanCamouflage(u8 battlerId); +bool32 IsTelekinesisBannedSpecies(u16 species); +bool32 CanUseLastResort(u8 battlerId); +bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType); +s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk); +s32 GetCritHitChance(s32 critChanceIndex); extern void (* const gBattleScriptingCommandsTable[])(void); extern const struct StatFractions gAccuracyStageRatios[]; diff --git a/include/battle_util.h b/include/battle_util.h index 9fa8996bb..415af1090 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -148,7 +148,7 @@ void BattleScriptPushCursorAndCallback(const u8 *BS_ptr); u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn); void ClearVariousBattlerFlags(u32 battler); void HandleAction_RunBattleScript(void); -u8 GetMoveTarget(u16 move, u8 setTarget); +u32 GetMoveTarget(u16 move, u8 setTarget); u8 IsMonDisobedient(void); void SwitchPartyOrderInGameMulti(u8 battler, u8 arg1); // new @@ -178,6 +178,7 @@ bool32 IsBattlerProtected(u32 battler, u32 move); bool32 IsMoveMakingContact(u32 move, u32 battlerAtk); bool32 IsHealBlockPreventingMove(u32 battler, u32 move); s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags); +bool32 MoveHasAdditionalEffectWithChance(u32 move, u32 moveEffect, u32 chance); bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument); u32 GetMoveSlot(u16 *moves, u32 move); u32 GetBattlerWeight(u32 battler); @@ -191,6 +192,7 @@ bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2); bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2); u32 GetBattlerHoldEffectParam(u32 battler); uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities); +uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef); bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect); uq4_12_t GetTypeModifier(u32 atkType, u32 defType); u8 GetBattlerType(u32 battler, u8 typeIndex); @@ -245,17 +247,24 @@ void TryClearRageAndFuryCutter(void); bool32 CanMegaEvolve(u32 battler); bool32 CanUltraBurst(u32 battler); bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move); +u32 SetRandomTarget(u32 battler); +bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect); +u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer); +u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter); +s32 CalculateMoveDamageVars(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier, + u32 weather, bool32 isCrit, u32 holdEffectAtk, u32 holdEffectDef, u32 abilityAtk, u32 abilityDef); + // battle_ai_util.h -bool32 IsHealingMove(u32 move); -void RecordKnownMove(u32 battlerId, u32 move); -s32 CountUsablePartyMons(u32 battlerId); -bool32 IsAiVsAiBattle(void); -void RecordLastUsedMoveBy(u32 battlerId, u32 move); -bool32 BattlerHasAi(u32 battlerId); -void ClearBattlerItemEffectHistory(u32 battlerId); -bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect); -void RecordAllMoves(u32 battler); +// bool32 IsHealingMove(u32 move); +// void RecordKnownMove(u32 battlerId, u32 move); +// s32 CountUsablePartyMons(u32 battlerId); +// bool32 IsAiVsAiBattle(void); +// void RecordLastUsedMoveBy(u32 battlerId, u32 move); +// bool32 BattlerHasAi(u32 battlerId); +// void ClearBattlerItemEffectHistory(u32 battlerId); +// bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect); +// void RecordAllMoves(u32 battler); // end battle_ai_util.h diff --git a/include/constants/battle.h b/include/constants/battle.h index 0d31d0ca9..38c495315 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -75,6 +75,7 @@ #define IS_BATTLE_TYPE_GHOST_WITH_SCOPE(flags) ((flags) & BATTLE_TYPE_GHOST && (flags) & BATTLE_TYPE_GHOST_UNVEILED) #define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))) #define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gTrainerBattleOpponent_B == 0xFFFF)) +#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER | BATTLE_TYPE_INGAME_PARTNER) #define RIVAL_BATTLE_HEAL_AFTER 1 #define RIVAL_BATTLE_TUTORIAL 3 diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index e6301d01b..e42403e16 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -15,38 +15,45 @@ #define AI_TYPE_MOVE 4 // type effectiveness -#define AI_EFFECTIVENESS_x4 160 -#define AI_EFFECTIVENESS_x2 80 -#define AI_EFFECTIVENESS_x1 40 -#define AI_EFFECTIVENESS_x0_5 20 -#define AI_EFFECTIVENESS_x0_25 10 +#define AI_EFFECTIVENESS_x8 7 +#define AI_EFFECTIVENESS_x4 6 +#define AI_EFFECTIVENESS_x2 5 +#define AI_EFFECTIVENESS_x1 4 +#define AI_EFFECTIVENESS_x0_5 3 +#define AI_EFFECTIVENESS_x0_25 2 +#define AI_EFFECTIVENESS_x0_125 1 #define AI_EFFECTIVENESS_x0 0 -// ai weather -#define AI_WEATHER_SUN 0 -#define AI_WEATHER_RAIN 1 -#define AI_WEATHER_SANDSTORM 2 -#define AI_WEATHER_HAIL 3 +// AI Flags. Most run specific functions to update score, new flags are used for internal logic in other scripts +#define AI_FLAG_CHECK_BAD_MOVE (1 << 0) +#define AI_FLAG_TRY_TO_FAINT (1 << 1) +#define AI_FLAG_CHECK_VIABILITY (1 << 2) +#define AI_FLAG_SETUP_FIRST_TURN (1 << 3) +#define AI_FLAG_RISKY (1 << 4) +#define AI_FLAG_PREFER_STRONGEST_MOVE (1 << 5) +#define AI_FLAG_PREFER_BATON_PASS (1 << 6) +#define AI_FLAG_DOUBLE_BATTLE (1 << 7) // removed, split between AI_FLAG_CHECK_BAD_MOVE & AI_FLAG_CHECK_GOOD_MOVE +#define AI_FLAG_HP_AWARE (1 << 8) +#define AI_FLAG_POWERFUL_STATUS (1 << 9) // AI prefers moves that set up field effects or side statuses, even if the user can faint the target +// New, Trainer Handicap Flags +#define AI_FLAG_NEGATE_UNAWARE (1 << 10) // AI is NOT aware of negating effects like wonder room, mold breaker, etc +#define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc +// New, Trainer Strategy Flags +#define AI_FLAG_HELP_PARTNER (1 << 12) // AI can try to help partner. If not set, will tend not to target partner +#define AI_FLAG_PREFER_STATUS_MOVES (1 << 13) // AI gets a score bonus for status moves. Should be combined with AI_FLAG_CHECK_BAD_MOVE to prevent using only status moves +#define AI_FLAG_STALL (1 << 14) // AI stalls battle and prefers secondary damage/trapping/etc. TODO not finished +#define AI_FLAG_SMART_SWITCHING (1 << 15) // AI includes a lot more switching checks. Automatically includes AI_FLAG_SMART_MON_CHOICES. +#define AI_FLAG_ACE_POKEMON (1 << 16) // AI has an Ace Pokemon. The last Pokemon in the party will not be used until it's the last one remaining. +#define AI_FLAG_OMNISCIENT (1 << 17) // AI has full knowledge of player moves, abilities, hold items +#define AI_FLAG_SMART_MON_CHOICES (1 << 18) // AI will make smarter decisions when choosing which mon to send out mid-battle and after a KO, which are separate decisions. Automatically included by AI_FLAG_SMART_SWITCHING. -// get_how_powerful_move_is -#define MOVE_POWER_DISCOURAGED 0 -#define MOVE_NOT_MOST_POWERFUL 1 -#define MOVE_MOST_POWERFUL 2 +#define AI_FLAG_COUNT 19 -// script's table id to bit -#define AI_FLAG_CHECK_BAD_MOVE (1 << 0) -#define AI_FLAG_CHECK_VIABILITY (1 << 1) -#define AI_FLAG_TRY_TO_FAINT (1 << 2) -#define AI_SCRIPT_SETUP_FIRST_TURN (1 << 3) -#define AI_SCRIPT_RISKY (1 << 4) -#define AI_SCRIPT_PREFER_STRONGEST_MOVE (1 << 5) -#define AI_SCRIPT_PREFER_BATON_PASS (1 << 6) -#define AI_SCRIPT_DOUBLE_BATTLE (1 << 7) -#define AI_SCRIPT_HP_AWARE (1 << 8) -#define AI_SCRIPT_UNKNOWN (1 << 9) -// 10 - 28 are not used -#define AI_SCRIPT_ROAMING (1 << 29) -#define AI_SCRIPT_SAFARI (1 << 30) -#define AI_SCRIPT_FIRST_BATTLE (1 << 31) +// 'other' ai logic flags +#define AI_FLAG_ROAMING (1 << 29) +#define AI_FLAG_SAFARI (1 << 30) +#define AI_FLAG_FIRST_BATTLE (1 << 31) + +#define AI_SCORE_DEFAULT 100 // Default score for all AI moves. #endif // GUARD_CONSTANTS_BATTLE_AI_H diff --git a/include/constants/global.h b/include/constants/global.h index 328b19193..0da441977 100644 --- a/include/constants/global.h +++ b/include/constants/global.h @@ -71,6 +71,7 @@ #define ITEM_NAME_LENGTH 14 #define ITEM_NAME_PLURAL_LENGTH ITEM_NAME_LENGTH + 2 // 2 is used for the instance where a word's suffix becomes y->ies #define POKEMON_NAME_LENGTH 10 +#define POKEMON_NAME_BUFFER_SIZE max(20, POKEMON_NAME_LENGTH + 1) // Frequently used buffer size. Larger than necessary #define PLAYER_NAME_LENGTH 7 #define MAIL_WORDS_COUNT 9 #define EASY_CHAT_BATTLE_WORDS_COUNT 6 diff --git a/include/pokemon.h b/include/pokemon.h index 2d22724d2..4fbdb690c 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -745,10 +745,11 @@ const struct FormChange *GetSpeciesFormChanges(u16 species); u8 CalculatePPWithBonus(u16 move, u8 ppBonuses, u8 moveIndex); void RemoveMonPPBonus(struct Pokemon *mon, u8 moveIndex); void RemoveBattleMonPPBonus(struct BattlePokemon *mon, u8 moveIndex); +void PokemonToBattleMon(struct Pokemon *src, struct BattlePokemon *dst); bool8 ExecuteTableBasedItemEffect(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex); bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex, bool8 usedByAI); u8 GetItemEffectParamOffset(u32 battler, u16 itemId, u8 effectByte, u8 effectBit); -// const u8 *Battle_PrintStatBoosterEffectMessage(u16 itemId); +u8 CanLearnTeachableMove(u16 species, u16 move); u8 GetNature(struct Pokemon *mon); u8 GetNatureFromPersonality(u32 personality); u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 type, u16 evolutionItem, struct Pokemon *tradePartner); @@ -820,5 +821,6 @@ bool8 HealStatusConditions(struct Pokemon *mon, u32 healMask, u8 battleId); u16 SanitizeSpeciesId(u16 species); bool32 IsSpeciesEnabled(u16 species); u32 GetUnownSpeciesId(u32 personality); +u8 CalculatePartyCount(struct Pokemon *party); #endif // GUARD_POKEMON_H diff --git a/ld_script.ld b/ld_script.ld index 405b50804..6d9980de3 100644 --- a/ld_script.ld +++ b/ld_script.ld @@ -199,7 +199,6 @@ SECTIONS { src/heal_location.o(.text); src/region_map.o(.text); src/image_processing_effects.o(.text); - src/battle_ai_script_commands.o(.text); src/wallclock.o(.text); src/fldeff_rocksmash.o(.text); src/fldeff_dig.o(.text); @@ -288,6 +287,8 @@ SECTIONS { src/itemfinder.o(.text); src/buy_menu_helpers.o(.text); src/slot_machine.o(.text); + src/battle_ai_main.o(.text); + src/battle_ai_util.o(.text); src/roamer.o(.text); src/mystery_gift_menu.o(.text); src/ereader_screen.o(.text); @@ -329,7 +330,6 @@ SECTIONS { data/battle_scripts_1.o(script_data); data/field_effect_scripts.o(script_data); data/battle_scripts_2.o(script_data); - data/battle_ai_scripts.o(script_data); data/mystery_event_script_cmd_table.o(script_data); } > ROM =0 @@ -429,6 +429,7 @@ SECTIONS { src/battle_controller_player.o(.rodata); src/battle_anim_smokescreen.o(.rodata); src/battle_controller_opponent.o(.rodata); + src/battle_ai_switch_items.o(.rodata); src/battle_controller_link_opponent.o(.rodata); src/pokemon.o(.rodata); src/trig.o(.rodata); @@ -514,7 +515,6 @@ SECTIONS { src/heal_location.o(.rodata); src/region_map.o(.rodata); src/image_processing_effects.o(.rodata); - src/battle_ai_script_commands.o(.rodata); src/wallclock.o(.rodata); src/fldeff_flash.o(.rodata); src/time_events.o(.rodata); @@ -588,6 +588,8 @@ SECTIONS { src/itemfinder.o(.rodata); src/buy_menu_helpers.o(.rodata); src/slot_machine.o(.rodata); + src/battle_ai_main.o(.rodata); + src/battle_ai_util.o(.rodata); src/roamer.o(.rodata); src/mystery_gift_menu.o(.rodata); src/ereader_screen.o(.rodata); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c new file mode 100644 index 000000000..2d1a4f558 --- /dev/null +++ b/src/battle_ai_main.c @@ -0,0 +1,5192 @@ +#include "global.h" +#include "main.h" +#include "malloc.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_ai_util.h" +#include "battle_ai_main.h" +#include "battle_controllers.h" +#include "battle_setup.h" +// #include "battle_z_move.h" +#include "data.h" +#include "event_data.h" +#include "item.h" +#include "pokemon.h" +#include "random.h" +#include "util.h" +#include "constants/abilities.h" +#include "constants/battle_ai.h" +#include "constants/battle_move_effects.h" +#include "constants/hold_effects.h" +#include "constants/moves.h" +#include "constants/items.h" +#include "constants/trainers.h" + +#define AI_ACTION_DONE (1 << 0) +#define AI_ACTION_FLEE (1 << 1) +#define AI_ACTION_WATCH (1 << 2) +#define AI_ACTION_DO_NOT_ATTACK (1 << 3) + +static u32 ChooseMoveOrAction_Singles(u32 battlerAi); +static u32 ChooseMoveOrAction_Doubles(u32 battlerAi); +static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battlerAi, u32 battlerDef); +static bool32 IsPinchBerryItemEffect(u32 holdEffect); + +// ewram +EWRAM_DATA const u8 *gAIScriptPtr = NULL; // Still used in contests +EWRAM_DATA u8 sBattler_AI = 0; + +// const rom data +static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_Safari(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); + + +static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) = +{ + [0] = AI_CheckBadMove, // AI_FLAG_CHECK_BAD_MOVE + [1] = AI_TryToFaint, // AI_FLAG_TRY_TO_FAINT + [2] = AI_CheckViability, // AI_FLAG_CHECK_VIABILITY + [3] = AI_SetupFirstTurn, // AI_FLAG_SETUP_FIRST_TURN + [4] = AI_Risky, // AI_FLAG_RISKY + [5] = AI_PreferStrongestMove, // AI_FLAG_PREFER_STRONGEST_MOVE + [6] = AI_PreferBatonPass, // AI_FLAG_PREFER_BATON_PASS + [7] = AI_DoubleBattle, // AI_FLAG_DOUBLE_BATTLE + [8] = AI_HPAware, // AI_FLAG_HP_AWARE + [9] = AI_PowerfulStatus, // AI_FLAG_POWERFUL_STATUS + [10] = NULL, // AI_FLAG_NEGATE_UNAWARE + [11] = NULL, // AI_FLAG_WILL_SUICIDE + [12] = NULL, // AI_FLAG_HELP_PARTNER + [13] = NULL, // Unused + [14] = NULL, // Unused + [15] = NULL, // Unused + [16] = NULL, // Unused + [17] = NULL, // Unused + [18] = NULL, // Unused + [19] = NULL, // Unused + [20] = NULL, // Unused + [21] = NULL, // Unused + [22] = NULL, // Unused + [23] = NULL, // Unused + [24] = NULL, // Unused + [25] = NULL, // Unused + [26] = NULL, // Unused + [27] = NULL, // Unused + [28] = NULL, // Unused + [29] = AI_Roaming, // AI_FLAG_ROAMING + [30] = AI_Safari, // AI_FLAG_SAFARI + [31] = AI_FirstBattle, // AI_FLAG_FIRST_BATTLE +}; + +// Functions +void BattleAI_SetupItems(void) +{ + s32 i; + u8 *data = (u8 *)BATTLE_HISTORY; + const u16 *items = GetTrainerItemsFromId(gTrainerBattleOpponent_A); + + for (i = 0; i < sizeof(struct BattleHistory); i++) + data[i] = 0; + + // Items are allowed to use in ONLY trainer battles. + if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER) + && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | BATTLE_TYPE_BATTLE_TOWER + | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_INGAME_PARTNER) + ) + ) + { + for (i = 0; i < MAX_TRAINER_ITEMS; i++) + { + if (items[i] != ITEM_NONE) + { + BATTLE_HISTORY->trainerItems[BATTLE_HISTORY->itemsNo] = items[i]; + BATTLE_HISTORY->itemsNo++; + } + } + } +} + +static u32 GetWildAiFlags(void) +{ + u32 avgLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL); + u32 flags = 0; + + if (IsDoubleBattle()) + avgLevel = (GetMonData(&gEnemyParty[0], MON_DATA_LEVEL) + GetMonData(&gEnemyParty[1], MON_DATA_LEVEL)) / 2; + + flags |= AI_FLAG_CHECK_BAD_MOVE; + if (avgLevel >= 20) + flags |= AI_FLAG_CHECK_VIABILITY; + if (avgLevel >= 60) + flags |= AI_FLAG_PREFER_STRONGEST_MOVE; + if (avgLevel >= 80) + flags |= AI_FLAG_HP_AWARE; + + if (B_VAR_WILD_AI_FLAGS != 0 && VarGet(B_VAR_WILD_AI_FLAGS) != 0) + flags |= VarGet(B_VAR_WILD_AI_FLAGS); + + return flags; +} + +static u32 GetAiFlags(u16 trainerId) +{ + u32 flags = 0; + + if (!(gBattleTypeFlags & BATTLE_TYPE_HAS_AI) && !IsWildMonSmart()) + return 0; + if (trainerId == 0xFFFF) + { + flags = GetWildAiFlags(); + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + flags = AI_FLAG_SAFARI; + else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) + flags = AI_FLAG_ROAMING; + else if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + flags = AI_FLAG_FIRST_BATTLE; + else if (gBattleTypeFlags & (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_TOWER)) + flags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT; + else + flags = GetTrainerAIFlagsFromId(trainerId); + } + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + flags |= AI_FLAG_DOUBLE_BATTLE; + } + + // Automatically includes AI_FLAG_SMART_MON_CHOICES to improve smart switching + if (flags & AI_FLAG_SMART_SWITCHING) + flags |= AI_FLAG_SMART_MON_CHOICES; + + return flags; +} + +void BattleAI_SetupFlags(void) +{ + if (IsAiVsAiBattle()) + AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId); + else + AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI + +#if DEBUG_OVERWORLD_MENU == TRUE + if (gIsDebugBattle) + { + AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags; + AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags; + return; + } +#endif + + if (IsWildMonSmart() && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))) + { + // smart wild AI + AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF); + AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF); + } + else + { + AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(gTrainerBattleOpponent_A); + if (gTrainerBattleOpponent_B != 0) + AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(gTrainerBattleOpponent_B); + else + AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT]; + } + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)); + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsAiVsAiBattle()) + { + AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT]; + } + else + { + AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = 0; // player + } +} + +// sBattler_AI set in ComputeBattleAiScores +void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) +{ + s32 i; + u8 moveLimitations; + u32 flags[MAX_BATTLERS_COUNT]; + + // Clear AI data but preserve the flags. + memcpy(&flags[0], &AI_THINKING_STRUCT->aiFlags[0], sizeof(u32) * MAX_BATTLERS_COUNT); + memset(AI_THINKING_STRUCT, 0, sizeof(struct AI_ThinkingStruct)); + memcpy(&AI_THINKING_STRUCT->aiFlags[0], &flags[0], sizeof(u32) * MAX_BATTLERS_COUNT); + + // Conditional score reset, unlike Ruby. + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (defaultScoreMoves & 1) + SET_SCORE(battler, i, AI_SCORE_DEFAULT); + else + SET_SCORE(battler, i, 0); + + defaultScoreMoves >>= 1; + } + + moveLimitations = AI_DATA->moveLimitations[battler]; + + // Ignore moves that aren't possible to use. + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (gBitTable[i] & moveLimitations) + SET_SCORE(battler, i, 0); + } + + //sBattler_AI = battler; + gBattlerTarget = SetRandomTarget(sBattler_AI); + gBattleStruct->aiChosenTarget[sBattler_AI] = gBattlerTarget; +} + +u32 BattleAI_ChooseMoveOrAction(void) +{ + u32 ret; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + ret = ChooseMoveOrAction_Singles(sBattler_AI); + else + ret = ChooseMoveOrAction_Doubles(sBattler_AI); + + // Clear protect structures, some flags may be set during AI calcs + // e.g. pranksterElevated from GetMovePriority + memset(&gProtectStructs, 0, MAX_BATTLERS_COUNT * sizeof(struct ProtectStruct)); + #if TESTING + TestRunner_Battle_CheckAiMoveScores(sBattler_AI); + #endif // TESTING + return ret; +} + +// damages/other info computed in GetAIDataAndCalcDmg +u32 ComputeBattleAiScores(u32 battler) +{ + sBattler_AI = battler; + BattleAI_SetupAIData(0xF, sBattler_AI); + return BattleAI_ChooseMoveOrAction(); +} + +static void CopyBattlerDataToAIParty(u32 bPosition, u32 side) +{ + u32 battler = GetBattlerAtPosition(bPosition); + struct AiPartyMon *aiMon = &AI_PARTY->mons[side][gBattlerPartyIndexes[battler]]; + struct BattlePokemon *bMon = &gBattleMons[battler]; + + aiMon->species = bMon->species; + aiMon->level = bMon->level; + aiMon->status = bMon->status1; + aiMon->gender = GetBattlerGender(battler); + aiMon->isFainted = FALSE; + aiMon->wasSentInBattle = TRUE; + aiMon->switchInCount++; +} + +void Ai_InitPartyStruct(void) +{ + u32 i; + bool32 isOmniscient = (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT) || (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT); + struct Pokemon *mon; + + AI_PARTY->count[B_SIDE_PLAYER] = gPlayerPartyCount; + AI_PARTY->count[B_SIDE_OPPONENT] = gEnemyPartyCount; + + // Save first 2 or 4(in doubles) mons + CopyBattlerDataToAIParty(B_POSITION_PLAYER_LEFT, B_SIDE_PLAYER); + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + CopyBattlerDataToAIParty(B_POSITION_PLAYER_RIGHT, B_SIDE_PLAYER); + + // If player's partner is AI, save opponent mons + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + CopyBattlerDataToAIParty(B_POSITION_OPPONENT_LEFT, B_SIDE_OPPONENT); + CopyBattlerDataToAIParty(B_POSITION_OPPONENT_RIGHT, B_SIDE_OPPONENT); + } + + // Find fainted mons + for (i = 0; i < AI_PARTY->count[B_SIDE_PLAYER]; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) + AI_PARTY->mons[B_SIDE_PLAYER][i].isFainted = TRUE; + + if (isOmniscient) + { + u32 j; + mon = &gPlayerParty[i]; + AI_PARTY->mons[B_SIDE_PLAYER][i].item = GetMonData(mon, MON_DATA_HELD_ITEM); + AI_PARTY->mons[B_SIDE_PLAYER][i].heldEffect = ItemId_GetHoldEffect(AI_PARTY->mons[B_SIDE_PLAYER][i].item); + AI_PARTY->mons[B_SIDE_PLAYER][i].ability = GetMonAbility(mon); + for (j = 0; j < MAX_MON_MOVES; j++) + AI_PARTY->mons[B_SIDE_PLAYER][i].moves[j] = GetMonData(mon, MON_DATA_MOVE1 + j); + } + } +} + +void Ai_UpdateSwitchInData(u32 battler) +{ + u32 i; + u32 side = GetBattlerSide(battler); + struct AiPartyMon *aiMon = &AI_PARTY->mons[side][gBattlerPartyIndexes[battler]]; + + // See if the switched-in mon has been already in battle + if (aiMon->wasSentInBattle) + { + if (aiMon->ability) + BATTLE_HISTORY->abilities[battler] = aiMon->ability; + if (aiMon->heldEffect) + BATTLE_HISTORY->itemEffects[battler] = aiMon->heldEffect; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (aiMon->moves[i]) + BATTLE_HISTORY->usedMoves[battler][i] = aiMon->moves[i]; + } + aiMon->switchInCount++; + aiMon->status = gBattleMons[battler].status1; // Copy status, because it could've been changed in battle. + } + else // If not, copy the newly switched-in mon in battle and clear battle history. + { + ClearBattlerMoveHistory(battler); + ClearBattlerAbilityHistory(battler); + ClearBattlerItemEffectHistory(battler); + CopyBattlerDataToAIParty(GetBattlerPosition(battler), side); + } +} + +void Ai_UpdateFaintData(u32 battler) +{ + struct AiPartyMon *aiMon = &AI_PARTY->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]]; + ClearBattlerMoveHistory(battler); + ClearBattlerAbilityHistory(battler); + ClearBattlerItemEffectHistory(battler); + aiMon->isFainted = TRUE; +} + +static void SetBattlerAiData(u32 battler, struct AiLogicData *aiData) +{ + u32 ability, holdEffect; + + ability = aiData->abilities[battler] = AI_DecideKnownAbilityForTurn(battler); + aiData->items[battler] = gBattleMons[battler].item; + holdEffect = aiData->holdEffects[battler] = AI_DecideHoldEffectForTurn(battler); + aiData->holdEffectParams[battler] = GetBattlerHoldEffectParam(battler); + aiData->predictedMoves[battler] = gLastMoves[battler]; + aiData->hpPercents[battler] = GetHealthPercentage(battler); + aiData->moveLimitations[battler] = CheckMoveLimitations(battler, 0, MOVE_LIMITATIONS_ALL); + aiData->speedStats[battler] = GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect); +} + +static u32 Ai_SetMoveAccuracy(struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef, u32 move) +{ + u32 accuracy; + u32 abilityAtk = aiData->abilities[battlerAtk]; + u32 abilityDef = aiData->abilities[battlerAtk]; + if (abilityAtk == ABILITY_NO_GUARD || abilityDef == ABILITY_NO_GUARD || gMovesInfo[move].accuracy == 0) // Moves with accuracy 0 or no guard ability always hit. + accuracy = 100; + else + accuracy = GetTotalAccuracy(battlerAtk, battlerDef, move, abilityAtk, abilityDef, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef]); + + return accuracy; +} + +static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u32 battlersCount) +{ + u32 battlerDef, i, weather; + u16 *moves; + + SaveBattlerData(battlerAtk); + moves = GetMovesArray(battlerAtk); + weather = AI_GetWeather(aiData); + + // Simulate dmg for both ai controlled mons and for player controlled mons. + for (battlerDef = 0; battlerDef < battlersCount; battlerDef++) + { + if (battlerAtk == battlerDef) + continue; + + SaveBattlerData(battlerDef); + for (i = 0; i < MAX_MON_MOVES; i++) + { + s32 dmg = 0; + u8 effectiveness = AI_EFFECTIVENESS_x0; + u32 move = moves[i]; + + if (move != 0 + && move != 0xFFFF + //&& gMovesInfo[move].power != 0 /* we want to get effectiveness and accuracy of status moves */ + && !(aiData->moveLimitations[battlerAtk] & gBitTable[i])) + { + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather); + aiData->moveAccuracy[battlerAtk][battlerDef][i] = Ai_SetMoveAccuracy(aiData, battlerAtk, battlerDef, move); + } + aiData->simulatedDmg[battlerAtk][battlerDef][i] = dmg; + aiData->effectiveness[battlerAtk][battlerDef][i] = effectiveness; + } + } +} + +void SetAiLogicDataForTurn(struct AiLogicData *aiData) +{ + u32 battlerAtk, battlersCount; + + memset(aiData, 0, sizeof(struct AiLogicData)); + if (!(gBattleTypeFlags & BATTLE_TYPE_HAS_AI) && !IsWildMonSmart()) + return; + + // Set delay timer to count how long it takes for AI to choose action/move + gBattleStruct->aiDelayTimer = *gMain.vblankCounter1; + + aiData->weatherHasEffect = WEATHER_HAS_EFFECT; + // get/assume all battler data and simulate AI damage + battlersCount = gBattlersCount; + for (battlerAtk = 0; battlerAtk < battlersCount; battlerAtk++) + { + if (!IsBattlerAlive(battlerAtk)) + continue; + + SetBattlerAiData(battlerAtk, aiData); + SetBattlerAiMovesData(aiData, battlerAtk, battlersCount); + } +} + +static bool32 AI_SwitchMonIfSuitable(u32 battler, bool32 doubleBattle) +{ + u32 monToSwitchId = AI_DATA->mostSuitableMonId[battler]; + if (monToSwitchId != PARTY_SIZE && IsValidForBattle(&GetBattlerParty(battler)[monToSwitchId])) + { + gBattleMoveDamage = monToSwitchId; + // Edge case: See if partner already chose to switch into the same mon + if (doubleBattle) + { + u32 partner = BATTLE_PARTNER(battler); + if (AI_DATA->shouldSwitchMon & gBitTable[partner] && AI_DATA->monToSwitchId[partner] == monToSwitchId) + { + return FALSE; + } + } + AI_DATA->shouldSwitchMon |= gBitTable[battler]; + AI_DATA->monToSwitchId[battler] = monToSwitchId; + return TRUE; + } + return FALSE; +} + +static bool32 AI_ShouldSwitchIfBadMoves(u32 battler, bool32 doubleBattle) +{ + u32 i, j; + // If can switch. + if (CountUsablePartyMons(battler) > 0 + && !IsBattlerTrapped(battler, TRUE) + && AI_THINKING_STRUCT->aiFlags[battler] & (AI_FLAG_CHECK_VIABILITY | AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_PREFER_BATON_PASS)) + { + // Consider switching if all moves are worthless to use. + if (GetTotalBaseStat(gBattleMons[battler].species) >= 310 // Mon is not weak. + && gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2) // Mon has more than 50% of its HP + { + s32 cap = AI_THINKING_STRUCT->aiFlags[battler] & (AI_FLAG_CHECK_VIABILITY) ? 95 : 93; + if (doubleBattle) + { + for (i = 0; i < MAX_BATTLERS_COUNT; i++) + { + if (i != battler && IsBattlerAlive(i)) + { + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (gBattleStruct->aiFinalScore[battler][i][j] > cap) + break; + } + if (j != MAX_MON_MOVES) + break; + } + } + if (i == MAX_BATTLERS_COUNT && AI_SwitchMonIfSuitable(battler, doubleBattle)) + return TRUE; + } + else + { + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (AI_THINKING_STRUCT->score[i] > cap) + break; + } + + if (i == MAX_MON_MOVES && AI_SwitchMonIfSuitable(battler, doubleBattle)) + return TRUE; + } + + } + + // Consider switching if your mon with truant is bodied by Protect spam. + // Or is using a double turn semi invulnerable move(such as Fly) and is faster. + if (GetBattlerAbility(battler) == ABILITY_TRUANT + && IsTruantMonVulnerable(battler, gBattlerTarget) + && gDisableStructs[battler].truantCounter + && gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2 + && AI_SwitchMonIfSuitable(battler, doubleBattle)) + { + return TRUE; + } + } + return FALSE; +} + +static u32 ChooseMoveOrAction_Singles(u32 battlerAi) +{ + u8 currentMoveArray[MAX_MON_MOVES]; + u8 consideredMoveArray[MAX_MON_MOVES]; + u32 numOfBestMoves; + s32 i; + u32 flags = AI_THINKING_STRUCT->aiFlags[battlerAi]; + + AI_DATA->partnerMove = 0; // no ally + while (flags != 0) + { + if (flags & 1) + { + BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battlerAi, gBattlerTarget); + } + flags >>= 1; + AI_THINKING_STRUCT->aiLogicId++; + } + + for (i = 0; i < MAX_MON_MOVES; i++) + { + gBattleStruct->aiFinalScore[battlerAi][gBattlerTarget][i] = AI_THINKING_STRUCT->score[i]; + } + + // Check special AI actions. + if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) + return AI_CHOICE_FLEE; + if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) + return AI_CHOICE_WATCH; + + // Switch mon if there are no good moves to use. + if (AI_ShouldSwitchIfBadMoves(battlerAi, FALSE)) + return AI_CHOICE_SWITCH; + + numOfBestMoves = 1; + currentMoveArray[0] = AI_THINKING_STRUCT->score[0]; + consideredMoveArray[0] = 0; + + for (i = 1; i < MAX_MON_MOVES; i++) + { + if (gBattleMons[battlerAi].moves[i] != MOVE_NONE) + { + // In ruby, the order of these if statements is reversed. + if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i]) + { + currentMoveArray[numOfBestMoves] = AI_THINKING_STRUCT->score[i]; + consideredMoveArray[numOfBestMoves++] = i; + } + if (currentMoveArray[0] < AI_THINKING_STRUCT->score[i]) + { + numOfBestMoves = 1; + currentMoveArray[0] = AI_THINKING_STRUCT->score[i]; + consideredMoveArray[0] = i; + } + } + } + return consideredMoveArray[Random() % numOfBestMoves]; +} + +static u32 ChooseMoveOrAction_Doubles(u32 battlerAi) +{ + s32 i, j; + u32 flags; + s32 bestMovePointsForTarget[MAX_BATTLERS_COUNT]; + u8 mostViableTargetsArray[MAX_BATTLERS_COUNT]; + u8 actionOrMoveIndex[MAX_BATTLERS_COUNT]; + s32 mostViableMovesScores[MAX_MON_MOVES]; + u8 mostViableMovesIndices[MAX_MON_MOVES]; + u32 mostViableTargetsNo; + u32 mostViableMovesNo; + s32 mostMovePoints; + + for (i = 0; i < MAX_BATTLERS_COUNT; i++) + { + if (i == battlerAi || gBattleMons[i].hp == 0) + { + actionOrMoveIndex[i] = 0xFF; + bestMovePointsForTarget[i] = -1; + } + else + { + BattleAI_SetupAIData(0xF, battlerAi); + + gBattlerTarget = i; + + AI_DATA->partnerMove = GetAllyChosenMove(battlerAi); + AI_THINKING_STRUCT->aiLogicId = 0; + AI_THINKING_STRUCT->movesetIndex = 0; + flags = AI_THINKING_STRUCT->aiFlags[sBattler_AI]; + + while (flags != 0) + { + if (flags & 1) + { + BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battlerAi, gBattlerTarget); + } + flags >>= 1; + AI_THINKING_STRUCT->aiLogicId++; + } + + if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) + { + actionOrMoveIndex[i] = AI_CHOICE_FLEE; + } + else if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) + { + actionOrMoveIndex[i] = AI_CHOICE_WATCH; + } + else + { + mostViableMovesScores[0] = AI_THINKING_STRUCT->score[0]; + mostViableMovesIndices[0] = 0; + mostViableMovesNo = 1; + for (j = 1; j < MAX_MON_MOVES; j++) + { + if (gBattleMons[battlerAi].moves[j] != 0) + { + if (!CanTargetBattler(battlerAi, i, gBattleMons[battlerAi].moves[j])) + continue; + + if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j]) + { + mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j]; + mostViableMovesIndices[mostViableMovesNo] = j; + mostViableMovesNo++; + } + if (mostViableMovesScores[0] < AI_THINKING_STRUCT->score[j]) + { + mostViableMovesScores[0] = AI_THINKING_STRUCT->score[j]; + mostViableMovesIndices[0] = j; + mostViableMovesNo = 1; + } + } + } + actionOrMoveIndex[i] = mostViableMovesIndices[Random() % mostViableMovesNo]; + bestMovePointsForTarget[i] = mostViableMovesScores[0]; + + // Don't use a move against ally if it has less than 100 points. + if (i == BATTLE_PARTNER(battlerAi) && bestMovePointsForTarget[i] < AI_SCORE_DEFAULT) + { + bestMovePointsForTarget[i] = -1; + } + } + + for (j = 0; j < MAX_MON_MOVES; j++) + { + gBattleStruct->aiFinalScore[battlerAi][gBattlerTarget][j] = AI_THINKING_STRUCT->score[j]; + } + } + } + + // Switch mon if all of the moves are bad to use against any of the target. + if (AI_ShouldSwitchIfBadMoves(battlerAi, TRUE)) + return AI_CHOICE_SWITCH; + + mostMovePoints = bestMovePointsForTarget[0]; + mostViableTargetsArray[0] = 0; + mostViableTargetsNo = 1; + + for (i = 1; i < MAX_BATTLERS_COUNT; i++) + { + if (mostMovePoints == bestMovePointsForTarget[i]) + { + mostViableTargetsArray[mostViableTargetsNo] = i; + mostViableTargetsNo++; + } + if (mostMovePoints < bestMovePointsForTarget[i]) + { + mostMovePoints = bestMovePointsForTarget[i]; + mostViableTargetsArray[0] = i; + mostViableTargetsNo = 1; + } + } + + gBattlerTarget = mostViableTargetsArray[Random() % mostViableTargetsNo]; + gBattleStruct->aiChosenTarget[battlerAi] = gBattlerTarget; + return actionOrMoveIndex[gBattlerTarget]; +} + +static inline bool32 ShouldConsiderMoveForBattler(u32 battlerAi, u32 battlerDef, u32 move) +{ + if (battlerAi == BATTLE_PARTNER(battlerDef)) + { + if (gMovesInfo[move].target == MOVE_TARGET_BOTH || gMovesInfo[move].target == MOVE_TARGET_OPPONENTS_FIELD) + return FALSE; + } + return TRUE; +} + +static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battlerAi, u32 battlerDef) +{ + do + { + if (gBattleMons[battlerAi].pp[aiThink->movesetIndex] == 0) + aiThink->moveConsidered = MOVE_NONE; + else + aiThink->moveConsidered = gBattleMons[battlerAi].moves[aiThink->movesetIndex]; + + // There is no point in calculating scores for all 3 battlers(2 opponents + 1 ally) with certain moves. + if (aiThink->moveConsidered != MOVE_NONE + && aiThink->score[aiThink->movesetIndex] > 0 + && ShouldConsiderMoveForBattler(battlerAi, battlerDef, aiThink->moveConsidered)) + { + if (aiThink->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable) + && sBattleAiFuncTable[aiThink->aiLogicId] != NULL) + { + // Call AI function + aiThink->score[aiThink->movesetIndex] = + sBattleAiFuncTable[aiThink->aiLogicId](battlerAi, + battlerDef, + aiThink->moveConsidered, + aiThink->score[aiThink->movesetIndex]); + } + } + else + { + aiThink->score[aiThink->movesetIndex] = 0; + } + aiThink->movesetIndex++; + } while (aiThink->movesetIndex < MAX_MON_MOVES && !(aiThink->aiAction & AI_ACTION_DO_NOT_ATTACK)); + + aiThink->movesetIndex = 0; +} + +// AI Score Functions +// AI_FLAG_CHECK_BAD_MOVE - decreases move scores +static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + // move data + s8 atkPriority = GetMovePriority(battlerAtk, move); + u32 moveEffect = gMovesInfo[move].effect; + s32 moveType; + u32 moveTarget = AI_GetBattlerMoveTargetType(battlerAtk, move); + struct AiLogicData *aiData = AI_DATA; + u32 effectiveness = aiData->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); + u32 i; + u32 weather; + u32 predictedMove = aiData->predictedMoves[battlerDef]; + + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + return score; + + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + + if (gMovesInfo[move].powderMove && !IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef])) + RETURN_SCORE_MINUS(10); + + if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) + RETURN_SCORE_MINUS(10); + + if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk)) + RETURN_SCORE_MINUS(10); + + // check if negates type + switch (effectiveness) + { + case AI_EFFECTIVENESS_x0: + RETURN_SCORE_MINUS(20); + break; + case AI_EFFECTIVENESS_x0_125: + case AI_EFFECTIVENESS_x0_25: + RETURN_SCORE_MINUS(10); + break; + } + + // check non-user target + if (!(moveTarget & MOVE_TARGET_USER)) + { + // target ability checks + if (!DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move)) + { + switch (aiData->abilities[battlerDef]) + { + case ABILITY_MAGIC_GUARD: + switch (moveEffect) + { + case EFFECT_POISON: + case EFFECT_WILL_O_WISP: + case EFFECT_TOXIC: + case EFFECT_LEECH_SEED: + ADJUST_SCORE(-5); + break; + case EFFECT_CURSE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) // Don't use Curse if you're a ghost type vs a Magic Guard user, they'll take no damage. + ADJUST_SCORE(-5); + break; + } + break; + case ABILITY_WONDER_GUARD: + if (effectiveness < AI_EFFECTIVENESS_x2) + return 0; + break; + case ABILITY_JUSTIFIED: + if (moveType == TYPE_DARK && !IS_MOVE_STATUS(move)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_RATTLED: + if (!IS_MOVE_STATUS(move) + && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_DAZZLING: + case ABILITY_QUEENLY_MAJESTY: + case ABILITY_ARMOR_TAIL: + if (atkPriority > 0) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_AROMA_VEIL: + if (IsAromaVeilProtectedMove(move)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_SWEET_VEIL: + if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_FLOWER_VEIL: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) && (IsNonVolatileStatusMoveEffect(moveEffect) || IsStatLoweringEffect(moveEffect))) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_MAGIC_BOUNCE: + if (gMovesInfo[move].magicCoatAffected) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_CONTRARY: + if (IsStatLoweringEffect(moveEffect)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_CLEAR_BODY: + case ABILITY_FULL_METAL_BODY: + case ABILITY_WHITE_SMOKE: + if (IsStatLoweringEffect(moveEffect)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_HYPER_CUTTER: + if ((moveEffect == EFFECT_ATTACK_DOWN || moveEffect == EFFECT_ATTACK_DOWN_2) + && move != MOVE_PLAY_NICE && move != MOVE_NOBLE_ROAR && move != MOVE_TEARFUL_LOOK && move != MOVE_VENOM_DRENCH) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_ILLUMINATE: + if (B_ILLUMINATE_EFFECT < GEN_9) + break; + // fallthrough + case ABILITY_KEEN_EYE: + case ABILITY_MINDS_EYE: + if (moveEffect == EFFECT_ACCURACY_DOWN || moveEffect == EFFECT_ACCURACY_DOWN_2) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_BIG_PECKS: + if (moveEffect == EFFECT_DEFENSE_DOWN || moveEffect == EFFECT_DEFENSE_DOWN_2) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_DEFIANT: + case ABILITY_COMPETITIVE: + if (IsStatLoweringEffect(moveEffect) && !IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + RETURN_SCORE_MINUS(8); + break; + case ABILITY_COMATOSE: + if (IsNonVolatileStatusMoveEffect(moveEffect)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_SHIELDS_DOWN: + if (IsShieldsDownProtected(battlerAtk) && IsNonVolatileStatusMoveEffect(moveEffect)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_LEAF_GUARD: + if ((AI_GetWeather(aiData) & B_WEATHER_SUN) + && aiData->holdEffects[battlerDef] != HOLD_EFFECT_UTILITY_UMBRELLA + && IsNonVolatileStatusMoveEffect(moveEffect)) + RETURN_SCORE_MINUS(10); + break; + } // def ability checks + + // target partner ability checks & not attacking partner + if (isDoubleBattle) + { + switch (aiData->abilities[BATTLE_PARTNER(battlerDef)]) + { + case ABILITY_LIGHTNING_ROD: + if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(move, aiData->abilities[battlerAtk])) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_STORM_DRAIN: + if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(move, aiData->abilities[battlerAtk])) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_MAGIC_BOUNCE: + if (gMovesInfo[move].magicCoatAffected && moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_SWEET_VEIL: + if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_FLOWER_VEIL: + if ((IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS)) && (IsNonVolatileStatusMoveEffect(moveEffect) || IsStatLoweringEffect(moveEffect))) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_AROMA_VEIL: + if (IsAromaVeilProtectedMove(move)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_DAZZLING: + case ABILITY_QUEENLY_MAJESTY: + case ABILITY_ARMOR_TAIL: + if (atkPriority > 0) + RETURN_SCORE_MINUS(10); + break; + } + } // def partner ability checks + } // ignore def ability check + + // gen7+ dark type mons immune to priority->elevated moves from prankster + if (B_PRANKSTER_DARK_TYPES >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) + && aiData->abilities[battlerAtk] == ABILITY_PRANKSTER && IS_MOVE_STATUS(move) + && !(moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER))) + RETURN_SCORE_MINUS(10); + + // terrain & effect checks + if (AI_IsTerrainAffected(battlerDef, STATUS_FIELD_ELECTRIC_TERRAIN)) + { + if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) + RETURN_SCORE_MINUS(20); + } + + if (AI_IsTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN)) + { + if (IsNonVolatileStatusMoveEffect(moveEffect) || IsConfusionMoveEffect(moveEffect)) + RETURN_SCORE_MINUS(20); + } + + if (AI_IsTerrainAffected(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN) && atkPriority > 0) + { + RETURN_SCORE_MINUS(20); + } + } // end check MOVE_TARGET_USER + +// the following checks apply to any target (including user) + + // throat chop check + if (gDisableStructs[battlerAtk].throatChopTimer && gMovesInfo[move].soundMove) + return 0; // Can't even select move at all + // heal block check + if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK && IsHealBlockPreventingMove(battlerAtk, move)) + return 0; // Can't even select heal blocked move + + // primal weather check + weather = AI_GetWeather(aiData); + if (weather & B_WEATHER_PRIMAL_ANY) + { + switch (move) + { + case MOVE_SUNNY_DAY: + case MOVE_RAIN_DANCE: + case MOVE_HAIL: + case MOVE_SANDSTORM: + RETURN_SCORE_MINUS(30); + } + + if (!IS_MOVE_STATUS(move)) + { + if (weather & B_WEATHER_SUN_PRIMAL) + { + if (moveType == TYPE_WATER) + RETURN_SCORE_MINUS(30); + } + else if (weather & B_WEATHER_RAIN_PRIMAL) + { + if (moveType == TYPE_FIRE) + RETURN_SCORE_MINUS(30); + } + } + } + + // check move effects + switch (moveEffect) + { + case EFFECT_HIT: // only applies to Vital Throw + if (gMovesInfo[move].priority < 0 && AI_STRIKES_FIRST(battlerAtk, battlerDef, move) && aiData->hpPercents[battlerAtk] < 40) + ADJUST_SCORE(-2); // don't want to move last + break; + default: + break; // check move damage + case EFFECT_SLEEP: + if (!AI_CanPutToSleep(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_EXPLOSION: + if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE)) + ADJUST_SCORE(-2); + + if (effectiveness == AI_EFFECTIVENESS_x0) + { + ADJUST_SCORE(-10); + } + else if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move)) + { + ADJUST_SCORE(-10); + } + else if (CountUsablePartyMons(battlerAtk) == 0) + { + if (CountUsablePartyMons(battlerDef) != 0) + ADJUST_SCORE(-10); + else + ADJUST_SCORE(-1); + } + break; + // stat raising effects + case EFFECT_ATTACK_UP: + case EFFECT_ATTACK_UP_2: + case EFFECT_ATTACK_UP_USER_ALLY: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + break; + case EFFECT_STUFF_CHEEKS: + if (ItemId_GetPocket(gBattleMons[battlerAtk].item) != POCKET_BERRY_POUCH) + return 0; // cannot even select + //fallthrough + case EFFECT_DEFENSE_UP: + case EFFECT_DEFENSE_UP_2: + case EFFECT_DEFENSE_UP_3: + case EFFECT_DEFENSE_CURL: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_DEF)) + ADJUST_SCORE(-10); + break; + case EFFECT_SPECIAL_ATTACK_UP: + case EFFECT_SPECIAL_ATTACK_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_3: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)) + ADJUST_SCORE(-10); + break; + case EFFECT_SPECIAL_DEFENSE_UP: + case EFFECT_SPECIAL_DEFENSE_UP_2: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) + ADJUST_SCORE(-10); + break; + case EFFECT_ACCURACY_UP: + case EFFECT_ACCURACY_UP_2: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ACC)) + ADJUST_SCORE(-10); + break; + case EFFECT_EVASION_UP: + case EFFECT_EVASION_UP_2: + case EFFECT_MINIMIZE: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_EVASION)) + ADJUST_SCORE(-10); + break; + case EFFECT_COSMIC_POWER: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_DEF)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) + ADJUST_SCORE(-8); + break; + case EFFECT_BULK_UP: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_DEF)) + ADJUST_SCORE(-8); + break; + case EFFECT_CALM_MIND: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) + ADJUST_SCORE(-8); + break; + case EFFECT_DRAGON_DANCE: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPEED)) + ADJUST_SCORE(-8); + break; + case EFFECT_COIL: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ACC)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-8); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_DEF)) + ADJUST_SCORE(-6); + break; + case EFFECT_ATTACK_ACCURACY_UP: //hone claws + if (aiData->abilities[battlerAtk] != ABILITY_CONTRARY) + { + if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE + && (gBattleMons[battlerAtk].statStages[STAT_ACC] >= MAX_STAT_STAGE || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL))) + ADJUST_SCORE(-10); + break; + } + else + { + ADJUST_SCORE(-10); + } + break; + case EFFECT_CHARGE: + if (gStatuses3[battlerAtk] & STATUS3_CHARGED_UP) + ADJUST_SCORE(-20); + else if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC)) + ADJUST_SCORE(-10); + else if (B_CHARGE_SPDEF_RAISE >= GEN_5 + && !BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) + ADJUST_SCORE(-5); + break; + case EFFECT_QUIVER_DANCE: + case EFFECT_GEOMANCY: + if (gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPEED)) + ADJUST_SCORE(-8); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) + ADJUST_SCORE(-6); + break; + case EFFECT_VICTORY_DANCE: + if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPEED)) + ADJUST_SCORE(-8); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_DEF)) + ADJUST_SCORE(-6); + break; + case EFFECT_SHIFT_GEAR: + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPEED)) + ADJUST_SCORE(-8); + break; + case EFFECT_SHELL_SMASH: + if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) + { + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_DEF)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) + ADJUST_SCORE(-8); + } + else + { + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)) + ADJUST_SCORE(-8); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPEED)) + ADJUST_SCORE(-6); + } + break; + case EFFECT_GROWTH: + case EFFECT_ATTACK_SPATK_UP: // work up + if ((!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) && !BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK)) + || (!HasDamagingMove(battlerAtk))) + ADJUST_SCORE(-10); + break; + case EFFECT_ROTOTILLER: + if (isDoubleBattle) + { + if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) + && AI_IsBattlerGrounded(battlerAtk) + && (BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK))) + && !(IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), TYPE_GRASS) + && AI_IsBattlerGrounded(BATTLE_PARTNER(battlerAtk)) + && aiData->abilities[BATTLE_PARTNER(battlerAtk)] != ABILITY_CONTRARY + && (BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_ATK) + || BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPATK)))) + { + ADJUST_SCORE(-10); + } + } + else if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) + && AI_IsBattlerGrounded(battlerAtk) + && (BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK)))) + { + ADJUST_SCORE(-10); + } + break; + case EFFECT_GEAR_UP: + if (aiData->abilities[battlerAtk] == ABILITY_PLUS || aiData->abilities[battlerAtk] == ABILITY_MINUS) + { + // same as growth, work up + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)) + ADJUST_SCORE(-8); + break; + } + else if (!isDoubleBattle) + { + ADJUST_SCORE(-10); // no partner and our stats wont rise, so don't use + } + + if (isDoubleBattle) + { + if (aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_PLUS || aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_MINUS) + { + if ((!BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_ATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + && (!BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL))) + ADJUST_SCORE(-10); + } + else if (aiData->abilities[battlerAtk] != ABILITY_PLUS && aiData->abilities[battlerAtk] != ABILITY_MINUS) + { + ADJUST_SCORE(-10); // nor our or our partner's ability is plus/minus + } + } + break; + case EFFECT_ACUPRESSURE: + if (DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || AreBattlersStatsMaxed(battlerDef)) + ADJUST_SCORE(-10); + break; + case EFFECT_MAGNETIC_FLUX: + if (aiData->abilities[battlerAtk] == ABILITY_PLUS || aiData->abilities[battlerAtk] == ABILITY_MINUS) + { + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_DEF)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) + ADJUST_SCORE(-8); + } + else if (!isDoubleBattle) + { + ADJUST_SCORE(-10); // our stats wont rise from this move + } + + if (isDoubleBattle) + { + if (aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_PLUS || aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_MINUS) + { + if (!BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_DEF)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPDEF)) + ADJUST_SCORE(-8); + } + else if (aiData->abilities[battlerAtk] != ABILITY_PLUS && aiData->abilities[battlerAtk] != ABILITY_MINUS) + { + ADJUST_SCORE(-10); // nor our or our partner's ability is plus/minus + } + } + break; + // stat lowering effects + case EFFECT_ATTACK_DOWN: + case EFFECT_ATTACK_DOWN_2: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK)) //|| !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + else if (aiData->abilities[battlerDef] == ABILITY_HYPER_CUTTER) + ADJUST_SCORE(-10); + break; + case EFFECT_DEFENSE_DOWN: + case EFFECT_DEFENSE_DOWN_2: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_DEF)) + ADJUST_SCORE(-10); + break; + case EFFECT_SPEED_DOWN: + case EFFECT_SPEED_DOWN_2: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPEED)) + ADJUST_SCORE(-10); + else if (aiData->abilities[battlerDef] == ABILITY_SPEED_BOOST) + ADJUST_SCORE(-10); + break; + case EFFECT_SPECIAL_ATTACK_DOWN: + case EFFECT_SPECIAL_ATTACK_DOWN_2: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPATK)) //|| !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + ADJUST_SCORE(-10); + break; + case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN_2: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPDEF)) + ADJUST_SCORE(-10); + break; + case EFFECT_ACCURACY_DOWN: + case EFFECT_ACCURACY_DOWN_2: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ACC)) + ADJUST_SCORE(-10); + else if (aiData->abilities[battlerDef] == ABILITY_KEEN_EYE || aiData->abilities[battlerDef] == ABILITY_MINDS_EYE + || (B_ILLUMINATE_EFFECT >= GEN_9 && aiData->abilities[battlerDef] == ABILITY_ILLUMINATE)) + ADJUST_SCORE(-8); + break; + case EFFECT_EVASION_DOWN: + case EFFECT_EVASION_DOWN_2: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_EVASION)) + ADJUST_SCORE(-10); + break; + case EFFECT_TICKLE: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK)) + ADJUST_SCORE(-10); + else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_DEF)) + ADJUST_SCORE(-8); + break; + case EFFECT_VENOM_DRENCH: + if (!(gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)) + { + ADJUST_SCORE(-10); + } + else + { + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPEED)) + ADJUST_SCORE(-10); + else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPATK)) + ADJUST_SCORE(-8); + else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK)) + ADJUST_SCORE(-6); + } + break; + case EFFECT_NOBLE_ROAR: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPATK)) + ADJUST_SCORE(-10); + else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK)) + ADJUST_SCORE(-8); + break; + case EFFECT_CAPTIVATE: + if (!AreBattlersOfOppositeGender(battlerAtk, battlerDef)) + ADJUST_SCORE(-10); + break; + // other + case EFFECT_HAZE: + if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + { + ADJUST_SCORE(-10); // partner already using haze + } + else + { + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[BATTLE_PARTNER(battlerAtk)].statStages[i] > DEFAULT_STAT_STAGE) + ADJUST_SCORE(-10); // Don't want to reset our boosted stats + } + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerDef].statStages[i] < DEFAULT_STAT_STAGE || gBattleMons[BATTLE_PARTNER(battlerDef)].statStages[i] < DEFAULT_STAT_STAGE) + ADJUST_SCORE(-10); //Don't want to reset enemy lowered stats + } + } + break; + case EFFECT_PRESENT: + case EFFECT_FIXED_DAMAGE_ARG: + case EFFECT_FOCUS_PUNCH: + // AI_CBM_HighRiskForDamage + if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) + ADJUST_SCORE(-10); + break; + case EFFECT_COUNTER: + case EFFECT_MIRROR_COAT: + if (IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) + ADJUST_SCORE(-1); + if (predictedMove == MOVE_NONE || GetBattleMoveCategory(predictedMove) == DAMAGE_CATEGORY_STATUS + || DoesSubstituteBlockMove(battlerAtk, BATTLE_PARTNER(battlerDef), predictedMove)) + ADJUST_SCORE(-10); + break; + + case EFFECT_ROAR: + if (CountUsablePartyMons(battlerDef) == 0) + ADJUST_SCORE(-10); + else if (aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS) + ADJUST_SCORE(-10); + break; + case EFFECT_TOXIC_THREAD: + if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPEED)) + ADJUST_SCORE(-1); // may still want to just poison + //fallthrough + case EFFECT_POISON: + case EFFECT_TOXIC: + if (!AI_CanPoison(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_LIGHT_SCREEN: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_LIGHTSCREEN + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_REFLECT: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_REFLECT + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_AURORA_VEIL: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove) + || !(weather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) + ADJUST_SCORE(-10); + break; + case EFFECT_OHKO: + if (B_SHEER_COLD_IMMUNITY >= GEN_7 && move == MOVE_SHEER_COLD && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE)) + return 0; + if (!ShouldTryOHKO(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move)) + ADJUST_SCORE(-10); + break; + case EFFECT_MIST: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_FOCUS_ENERGY: + if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY_ANY) + ADJUST_SCORE(-10); + break; + case EFFECT_CONFUSE: + case EFFECT_SWAGGER: + case EFFECT_FLATTER: + if (!AI_CanConfuse(battlerAtk, battlerDef, aiData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_PARALYZE: + if (!AI_CanParalyze(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_SUBSTITUTE: + if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE || aiData->abilities[battlerDef] == ABILITY_INFILTRATOR) + ADJUST_SCORE(-8); + else if (aiData->hpPercents[battlerAtk] <= 25) + ADJUST_SCORE(-10); + else if (HasSubstituteIgnoringMove(battlerDef)) + ADJUST_SCORE(-8); + break; + case EFFECT_LEECH_SEED: + if (gStatuses3[battlerDef] & STATUS3_LEECHSEED + || IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + else if (aiData->abilities[battlerDef] == ABILITY_LIQUID_OOZE) + ADJUST_SCORE(-3); + break; + case EFFECT_DISABLE: + if (gDisableStructs[battlerDef].disableTimer == 0 + && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) + && !PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + { + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first + { + if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) + ADJUST_SCORE(-10); // no anticipated move to disable + } + else if (predictedMove == MOVE_NONE) + { + ADJUST_SCORE(-10); + } + } + else + { + ADJUST_SCORE(-10); + } + break; + case EFFECT_ENCORE: + if (gDisableStructs[battlerDef].encoreTimer == 0 + && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) + && !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + { + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first + { + if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) + ADJUST_SCORE(-10); // no anticipated move to encore + } + else if (predictedMove == MOVE_NONE) + { + ADJUST_SCORE(-10); + } + } + else + { + ADJUST_SCORE(-10); + } + break; + case EFFECT_SNORE: + case EFFECT_SLEEP_TALK: + if (IsWakeupTurn(battlerAtk) || !AI_IsBattlerAsleepOrComatose(battlerAtk)) + ADJUST_SCORE(-10); // if mon will wake up, is not asleep, or is not comatose + break; + case EFFECT_MEAN_LOOK: + if (IsBattlerTrapped(battlerDef, TRUE) || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_NIGHTMARE: + if (gBattleMons[battlerDef].status2 & STATUS2_NIGHTMARE) + ADJUST_SCORE(-10); + else if (!AI_IsBattlerAsleepOrComatose(battlerDef)) + ADJUST_SCORE(-8); + else if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_CURSE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) + { + if (gBattleMons[battlerDef].status2 & STATUS2_CURSED + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + else if (aiData->hpPercents[battlerAtk] <= 50) + ADJUST_SCORE(-6); + } + else // regular curse + { + if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_DEF)) + ADJUST_SCORE(-8); + } + break; + case EFFECT_SPIKES: + if (gSideTimers[GetBattlerSide(battlerDef)].spikesAmount >= 3) + ADJUST_SCORE(-10); + else if (PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove) + && gSideTimers[GetBattlerSide(battlerDef)].spikesAmount == 2) + ADJUST_SCORE(-10); // only one mon needs to set up the last layer of Spikes + break; + case EFFECT_STEALTH_ROCK: + if (gSideTimers[GetBattlerSide(battlerDef)].stealthRockAmount > 0 + || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) //Only one mon needs to set up Stealth Rocks + ADJUST_SCORE(-10); + break; + case EFFECT_TOXIC_SPIKES: + if (gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount >= 2) + ADJUST_SCORE(-10); + else if (PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount == 1) + ADJUST_SCORE(-10); // only one mon needs to set up the last layer of Toxic Spikes + break; + case EFFECT_STICKY_WEB: + if (gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) + ADJUST_SCORE(-10); + else if (PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) + ADJUST_SCORE(-10); // only one mon needs to set up Sticky Web + break; + case EFFECT_FORESIGHT: + if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 + || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-9); + break; + case EFFECT_PERISH_SONG: + if (isDoubleBattle) + { + if (CountUsablePartyMons(battlerAtk) == 0 + && aiData->abilities[battlerAtk] != ABILITY_SOUNDPROOF + && aiData->abilities[BATTLE_PARTNER(battlerAtk)] != ABILITY_SOUNDPROOF + && CountUsablePartyMons(FOE(battlerAtk)) >= 1) + { + ADJUST_SCORE(-10); //Don't wipe your team if you're going to lose + } + else if ((!IsBattlerAlive(FOE(battlerAtk)) || aiData->abilities[FOE(battlerAtk)] == ABILITY_SOUNDPROOF + || gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG) + && (!IsBattlerAlive(BATTLE_PARTNER(FOE(battlerAtk))) || aiData->abilities[BATTLE_PARTNER(FOE(battlerAtk))] == ABILITY_SOUNDPROOF + || gStatuses3[BATTLE_PARTNER(FOE(battlerAtk))] & STATUS3_PERISH_SONG)) + { + ADJUST_SCORE(-10); //Both enemies are perish songed + } + else if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + { + ADJUST_SCORE(-10); + } + } + else + { + if (CountUsablePartyMons(battlerAtk) == 0 && aiData->abilities[battlerAtk] != ABILITY_SOUNDPROOF + && CountUsablePartyMons(battlerDef) >= 1) + ADJUST_SCORE(-10); + + if (gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG || aiData->abilities[FOE(battlerAtk)] == ABILITY_SOUNDPROOF) + ADJUST_SCORE(-10); + } + break; + case EFFECT_SANDSTORM: + if (weather & (B_WEATHER_SANDSTORM | B_WEATHER_PRIMAL_ANY) + || IsMoveEffectWeather(aiData->partnerMove)) + ADJUST_SCORE(-8); + break; + case EFFECT_SUNNY_DAY: + if (weather & (B_WEATHER_SUN | B_WEATHER_PRIMAL_ANY) + || IsMoveEffectWeather(aiData->partnerMove)) + ADJUST_SCORE(-8); + break; + case EFFECT_RAIN_DANCE: + if (weather & (B_WEATHER_RAIN | B_WEATHER_PRIMAL_ANY) + || IsMoveEffectWeather(aiData->partnerMove)) + ADJUST_SCORE(-8); + break; + case EFFECT_HAIL: + if (weather & (B_WEATHER_HAIL | B_WEATHER_PRIMAL_ANY) + || IsMoveEffectWeather(aiData->partnerMove)) + ADJUST_SCORE(-8); + else if (weather & B_WEATHER_SNOW) + ADJUST_SCORE(-2); // mainly to prevent looping between hail and snow + break; + case EFFECT_SNOWSCAPE: + if (weather & (B_WEATHER_SNOW | B_WEATHER_PRIMAL_ANY) + || IsMoveEffectWeather(aiData->partnerMove)) + ADJUST_SCORE(-8); + else if (weather & B_WEATHER_HAIL) + ADJUST_SCORE(-2); // mainly to prevent looping between hail and snow + break; + case EFFECT_ATTRACT: + if (!AI_CanBeInfatuated(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(-10); + break; + case EFFECT_SAFEGUARD: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_SAFEGUARD + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_MAGNITUDE: + if (aiData->abilities[battlerDef] == ABILITY_LEVITATE) + ADJUST_SCORE(-10); + break; + case EFFECT_PARTING_SHOT: + if (CountUsablePartyMons(battlerAtk) == 0) + ADJUST_SCORE(-10); + break; + case EFFECT_BATON_PASS: + if (CountUsablePartyMons(battlerAtk) == 0) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE + || (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING | STATUS3_MAGNET_RISE | STATUS3_POWER_TRICK)) + || AnyStatIsRaised(battlerAtk)) + break; + else + ADJUST_SCORE(-6); + break; + case EFFECT_HIT_ESCAPE: + break; + case EFFECT_BELLY_DRUM: + case EFFECT_FILLET_AWAY: + if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) + ADJUST_SCORE(-10); + else if (aiData->hpPercents[battlerAtk] <= 60) + ADJUST_SCORE(-10); + break; + case EFFECT_FUTURE_SIGHT: + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_FUTUREATTACK + || gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_FUTUREATTACK) + ADJUST_SCORE(-12); + else + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_TELEPORT: + ADJUST_SCORE(-10); + break; + case EFFECT_FIRST_TURN_ONLY: + if (!gDisableStructs[battlerAtk].isFirstTurn) + ADJUST_SCORE(-10); + break; + case EFFECT_STOCKPILE: + if (gDisableStructs[battlerAtk].stockpileCounter >= 3) + ADJUST_SCORE(-10); + break; + case EFFECT_SWALLOW: + if (gDisableStructs[battlerAtk].stockpileCounter == 0) + { + ADJUST_SCORE(-10); + } + else + { + if (AtMaxHp(battlerAtk)) + ADJUST_SCORE(-10); + else if (aiData->hpPercents[battlerAtk] >= 80) + ADJUST_SCORE(-5); // do it if nothing better + } + break; + case EFFECT_TORMENT: + if (gBattleMons[battlerDef].status2 & STATUS2_TORMENT + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + { + ADJUST_SCORE(-10); + break; + } + if (B_MENTAL_HERB >= GEN_5 && aiData->holdEffects[battlerDef] == HOLD_EFFECT_MENTAL_HERB) + ADJUST_SCORE(-6); + break; + case EFFECT_WILL_O_WISP: + if (!AI_CanBurn(battlerAtk, battlerDef, aiData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_MEMENTO: + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE && gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE) + ADJUST_SCORE(-10); + break; + case EFFECT_FOLLOW_ME: + case EFFECT_HELPING_HAND: + if (!isDoubleBattle + || !IsBattlerAlive(BATTLE_PARTNER(battlerAtk)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove) + || (aiData->partnerMove != MOVE_NONE && IS_MOVE_STATUS(aiData->partnerMove)) + || *(gBattleStruct->monToSwitchIntoId + BATTLE_PARTNER(battlerAtk)) != PARTY_SIZE) //Partner is switching out. + ADJUST_SCORE(-10); + break; + case EFFECT_TRICK: + case EFFECT_KNOCK_OFF: + if (aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD) + ADJUST_SCORE(-10); + break; + case EFFECT_INGRAIN: + if (gStatuses3[battlerAtk] & STATUS3_ROOTED) + ADJUST_SCORE(-10); + break; + case EFFECT_AQUA_RING: + if (gStatuses3[battlerAtk] & STATUS3_AQUA_RING) + ADJUST_SCORE(-10); + break; + case EFFECT_RECYCLE: + if (GetUsedHeldItem(battlerAtk) == 0 || gBattleMons[battlerAtk].item != 0) + ADJUST_SCORE(-10); + break; + case EFFECT_IMPRISON: + if (gStatuses3[battlerAtk] & STATUS3_IMPRISONED_OTHERS) + ADJUST_SCORE(-10); + break; + case EFFECT_REFRESH: + if (!(gBattleMons[battlerDef].status1 & (STATUS1_PSN_ANY | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_FROSTBITE))) + ADJUST_SCORE(-10); + break; + case EFFECT_PSYCHO_SHIFT: + if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_CanPoison(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && !AI_CanBurn(battlerAtk, battlerDef, + aiData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && !AI_CanGiveFrostbite(battlerAtk, battlerDef, + aiData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_CanPutToSleep(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + else + ADJUST_SCORE(-10); // attacker has no status to transmit + break; + case EFFECT_MUD_SPORT: + if (gFieldStatuses & STATUS_FIELD_MUDSPORT + || gStatuses4[battlerAtk] & STATUS4_MUD_SPORT + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_WATER_SPORT: + if (gFieldStatuses & STATUS_FIELD_WATERSPORT + || gStatuses4[battlerAtk] & STATUS4_WATER_SPORT + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_ABSORB: + if (aiData->abilities[battlerDef] == ABILITY_LIQUID_OOZE) + ADJUST_SCORE(-6); + break; + case EFFECT_STRENGTH_SAP: + if (aiData->abilities[battlerDef] == ABILITY_CONTRARY) + ADJUST_SCORE(-10); + else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK)) + ADJUST_SCORE(-10); + break; + case EFFECT_COPYCAT: + case EFFECT_MIRROR_MOVE: + return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); + case EFFECT_FLOWER_SHIELD: + if (!IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) + && !(isDoubleBattle && IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), TYPE_GRASS))) + ADJUST_SCORE(-10); + break; + case EFFECT_AROMATIC_MIST: + if (!isDoubleBattle || gBattleMons[BATTLE_PARTNER(battlerAtk)].hp == 0 || !BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPDEF)) + ADJUST_SCORE(-10); + break; + case EFFECT_BIDE: + if (!HasDamagingMove(battlerDef) + || aiData->hpPercents[battlerAtk] < 30 //Close to death + || gBattleMons[battlerDef].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) //No point in biding if can't take damage + ADJUST_SCORE(-10); + break; + case EFFECT_HIT_SWITCH_TARGET: + if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); // don't scare away pokemon twice + else if (aiData->hpPercents[battlerDef] < 10 && GetBattlerSecondaryDamage(battlerDef)) + ADJUST_SCORE(-10); // don't blow away mon that will faint soon + else if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) + ADJUST_SCORE(-10); + break; + case EFFECT_CONVERSION: + //Check first move type + if (IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[gBattleMons[battlerAtk].moves[0]].type)) + ADJUST_SCORE(-10); + break; + case EFFECT_REST: + if (!AI_CanSleep(battlerAtk, aiData->abilities[battlerAtk])) + ADJUST_SCORE(-10); + //fallthrough + case EFFECT_RESTORE_HP: + case EFFECT_SOFTBOILED: + case EFFECT_ROOST: + if (AtMaxHp(battlerAtk)) + ADJUST_SCORE(-10); + else if (aiData->hpPercents[battlerAtk] >= 90) + ADJUST_SCORE(-9); //No point in healing, but should at least do it if nothing better + break; + case EFFECT_MORNING_SUN: + case EFFECT_SYNTHESIS: + case EFFECT_MOONLIGHT: + if ((AI_GetWeather(aiData) & (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_HAIL))) + ADJUST_SCORE(-3); + else if (AtMaxHp(battlerAtk)) + ADJUST_SCORE(-10); + else if (aiData->hpPercents[battlerAtk] >= 90) + ADJUST_SCORE(-9); //No point in healing, but should at least do it if nothing better + break; + case EFFECT_PURIFY: + if (!(gBattleMons[battlerDef].status1 & STATUS1_ANY)) + ADJUST_SCORE(-10); + else if (battlerDef == BATTLE_PARTNER(battlerAtk)) + break; //Always heal your ally + else if (AtMaxHp(battlerAtk)) + ADJUST_SCORE(-10); + else if (aiData->hpPercents[battlerAtk] >= 90) + ADJUST_SCORE(-8); //No point in healing, but should at least do it if nothing better + break; + case EFFECT_RECOIL_IF_MISS: + if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && AI_DATA->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] < 75) + ADJUST_SCORE(-6); + break; + case EFFECT_TRANSFORM: + if (gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED + || (gBattleMons[battlerDef].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE))) //Leave out Illusion b/c AI is supposed to be fooled + ADJUST_SCORE(-10); + break; + case EFFECT_SPITE: + case EFFECT_MIMIC: + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first + { + if (gLastMoves[battlerDef] == MOVE_NONE + || gLastMoves[battlerDef] == 0xFFFF) + ADJUST_SCORE(-10); + } + else if (predictedMove == MOVE_NONE) + { + // TODO predicted move separate from gLastMoves + ADJUST_SCORE(-10); + } + break; + case EFFECT_METRONOME: + break; + + case EFFECT_CONVERSION_2: + //TODO + break; + case EFFECT_LOCK_ON: + if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS + || aiData->abilities[battlerAtk] == ABILITY_NO_GUARD + || aiData->abilities[battlerDef] == ABILITY_NO_GUARD + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_LASER_FOCUS: + if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS) + ADJUST_SCORE(-10); + else if (aiData->abilities[battlerDef] == ABILITY_SHELL_ARMOR || aiData->abilities[battlerDef] == ABILITY_BATTLE_ARMOR) + ADJUST_SCORE(-8); + break; + case EFFECT_SKETCH: + if (gLastMoves[battlerDef] == MOVE_NONE) + ADJUST_SCORE(-10); + break; + case EFFECT_DESTINY_BOND: + if (gBattleMons[battlerDef].status2 & STATUS2_DESTINY_BOND) + ADJUST_SCORE(-10); + break; + case EFFECT_HEAL_BELL: + if (!AnyPartyMemberStatused(battlerAtk, gMovesInfo[move].soundMove) || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_ENDURE: + if (gBattleMons[battlerAtk].hp == 1 || GetBattlerSecondaryDamage(battlerAtk)) //Don't use Endure if you'll die after using it + ADJUST_SCORE(-10); + break; + case EFFECT_PROTECT: + { + bool32 decreased = FALSE; + switch (move) + { + case MOVE_QUICK_GUARD: + case MOVE_WIDE_GUARD: + case MOVE_CRAFTY_SHIELD: + if (!isDoubleBattle) + { + ADJUST_SCORE(-10); + decreased = TRUE; + } + break; + case MOVE_MAT_BLOCK: + if (!gDisableStructs[battlerAtk].isFirstTurn) + { + ADJUST_SCORE(-10); + decreased = TRUE; + } + break; + } // move check + + if (decreased) + break; + if (IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef])) + { + ADJUST_SCORE(-10); + break; + } + + if (move != MOVE_QUICK_GUARD + && move != MOVE_WIDE_GUARD + && move != MOVE_CRAFTY_SHIELD) //These moves have infinite usage + { + if (GetBattlerSecondaryDamage(battlerAtk) >= gBattleMons[battlerAtk].hp + && aiData->abilities[battlerDef] != ABILITY_MOXIE + && aiData->abilities[battlerDef] != ABILITY_BEAST_BOOST) + { + ADJUST_SCORE(-10); //Don't protect if you're going to faint after protecting + } + else if (gDisableStructs[battlerAtk].protectUses == 1 && Random() % 100 < 50) + { + if (!isDoubleBattle) + ADJUST_SCORE(-6); + else + ADJUST_SCORE(-10); //Don't try double protecting in doubles + } + else if (gDisableStructs[battlerAtk].protectUses >= 2) + { + ADJUST_SCORE(-10); + } + } + + /*if (AI_THINKING_STRUCT->aiFlags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI + && IS_DOUBLE_BATTLE) //Make the regular AI know how to use Protect minimally in Doubles + { + u8 shouldProtect = ShouldProtect(battlerAtk, battlerDef, move); + if (shouldProtect == USE_PROTECT || shouldProtect == PROTECT_FROM_FOES) + IncreaseFoeProtectionViability(&viability, 0xFF, battlerAtk, battlerDef); + else if (shouldProtect == PROTECT_FROM_ALLIES) + IncreaseAllyProtectionViability(&viability, 0xFF); + }*/ + } + break; + case EFFECT_MIRACLE_EYE: + if (gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED) + ADJUST_SCORE(-10); + + if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 + || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)) + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-9); + break; + case EFFECT_DEFOG: + if (gSideStatuses[GetBattlerSide(battlerDef)] + & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST) + || gSideTimers[GetBattlerSide(battlerDef)].auroraVeilTimer != 0 + || gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY) + { + if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + { + ADJUST_SCORE(-10); //Only need one hazards removal + break; + } + } + + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_HAZARDS_ANY) + { + ADJUST_SCORE(-10); //Don't blow away opposing hazards + break; + } + + if (isDoubleBattle) + { + if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // partner is going to set up hazards + && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerAtk, aiData->partnerMove) == AI_IS_FASTER) // partner is going to set up before the potential Defog + { + ADJUST_SCORE(-10); + break; // Don't use Defog if partner is going to set up hazards + } + } + + // evasion check + if (gBattleMons[battlerDef].statStages[STAT_EVASION] == MIN_STAT_STAGE + || ((aiData->abilities[battlerDef] == ABILITY_CONTRARY) && !IS_TARGETING_PARTNER(battlerAtk, battlerDef))) // don't want to raise target stats unless its your partner + ADJUST_SCORE(-10); + break; + case EFFECT_PSYCH_UP: // haze stats check + { + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[BATTLE_PARTNER(battlerAtk)].statStages[i] > DEFAULT_STAT_STAGE) + ADJUST_SCORE(-10); // Don't want to reset our boosted stats + } + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerDef].statStages[i] < DEFAULT_STAT_STAGE || gBattleMons[BATTLE_PARTNER(battlerDef)].statStages[i] < DEFAULT_STAT_STAGE) + ADJUST_SCORE(-10); //Don't want to copy enemy lowered stats + } + } + break; + case EFFECT_SEMI_INVULNERABLE: + if (predictedMove != MOVE_NONE + && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER + && gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE) + ADJUST_SCORE(-10); // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you + + if (BattlerWillFaintFromWeather(battlerAtk, aiData->abilities[battlerAtk]) + && (move == MOVE_FLY || move == MOVE_BOUNCE)) + ADJUST_SCORE(-10); // Attacker will faint while in the air + break; + case EFFECT_HEALING_WISH: //healing wish, lunar dance + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + else if (IsPartyFullyHealedExceptBattler(battlerAtk)) + ADJUST_SCORE(-10); + break; + case EFFECT_FINAL_GAMBIT: + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_NATURE_POWER: + return AI_CheckBadMove(battlerAtk, battlerDef, GetNaturePowerMove(), score); + case EFFECT_TAUNT: + if (gDisableStructs[battlerDef].tauntTimer > 0 + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_BESTOW: + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_NONE + || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item)) // AI knows its own item + ADJUST_SCORE(-10); + break; + case EFFECT_ROLE_PLAY: + if (aiData->abilities[battlerAtk] == aiData->abilities[battlerDef] + || aiData->abilities[battlerDef] == ABILITY_NONE + || gAbilitiesInfo[aiData->abilities[battlerAtk]].cantBeSuppressed + || gAbilitiesInfo[aiData->abilities[battlerDef]].cantBeCopied) + ADJUST_SCORE(-10); + else if (IsAbilityOfRating(aiData->abilities[battlerAtk], 5)) + ADJUST_SCORE(-4); + break; + case EFFECT_WISH: + if (gWishFutureKnock.wishCounter[battlerAtk] != 0) + ADJUST_SCORE(-10); + break; + case EFFECT_ASSIST: + if (CountUsablePartyMons(battlerAtk) == 0) + ADJUST_SCORE(-10); // no teammates to assist from + break; + case EFFECT_MAGIC_COAT: + if (!HasMagicCoatAffectedMove(battlerDef)) + ADJUST_SCORE(-10); + break; + case EFFECT_YAWN: + if (gStatuses3[battlerDef] & STATUS3_YAWN) + ADJUST_SCORE(-10); + else if (!AI_CanPutToSleep(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_SKILL_SWAP: + if (aiData->abilities[battlerAtk] == ABILITY_NONE || aiData->abilities[battlerDef] == ABILITY_NONE + || gAbilitiesInfo[aiData->abilities[battlerAtk]].cantBeSwapped + || gAbilitiesInfo[aiData->abilities[battlerDef]].cantBeSwapped + || aiData->holdEffects[battlerDef] == HOLD_EFFECT_ABILITY_SHIELD) + ADJUST_SCORE(-10); + break; + case EFFECT_WORRY_SEED: + if (aiData->abilities[battlerDef] == ABILITY_INSOMNIA + || gAbilitiesInfo[aiData->abilities[battlerDef]].cantBeOverwritten + || aiData->holdEffects[battlerDef] == HOLD_EFFECT_ABILITY_SHIELD) + ADJUST_SCORE(-10); + break; + case EFFECT_GASTRO_ACID: + if (gStatuses3[battlerDef] & STATUS3_GASTRO_ACID + || gAbilitiesInfo[aiData->abilities[battlerDef]].cantBeSuppressed) + ADJUST_SCORE(-10); + break; + case EFFECT_ENTRAINMENT: + if (aiData->abilities[battlerAtk] == ABILITY_NONE + || gAbilitiesInfo[aiData->abilities[battlerAtk]].cantBeCopied + || gAbilitiesInfo[aiData->abilities[battlerDef]].cantBeOverwritten + || aiData->holdEffects[battlerAtk] == HOLD_EFFECT_ABILITY_SHIELD) + ADJUST_SCORE(-10); + break; + case EFFECT_SIMPLE_BEAM: + if (aiData->abilities[battlerDef] == ABILITY_SIMPLE + || gAbilitiesInfo[aiData->abilities[battlerDef]].cantBeOverwritten + || aiData->holdEffects[battlerDef] == HOLD_EFFECT_ABILITY_SHIELD) + ADJUST_SCORE(-10); + break; + case EFFECT_SNATCH: + if (!HasSnatchAffectedMove(battlerDef) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_POWER_TRICK: + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerAtk].defense >= gBattleMons[battlerAtk].attack && !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(-10); + break; + case EFFECT_POWER_SWAP: // Don't use if attacker's stat stages are higher than opponents + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= gBattleMons[battlerDef].statStages[STAT_ATK] + && gBattleMons[battlerAtk].statStages[STAT_SPATK] >= gBattleMons[battlerDef].statStages[STAT_SPATK]) + ADJUST_SCORE(-10); + break; + case EFFECT_GUARD_SWAP: // Don't use if attacker's stat stages are higher than opponents + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= gBattleMons[battlerDef].statStages[STAT_DEF] + && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= gBattleMons[battlerDef].statStages[STAT_SPDEF]) + ADJUST_SCORE(-10); + break; + case EFFECT_SPEED_SWAP: + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + { + ADJUST_SCORE(-10); + } + else + { + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && (gBattleMons[battlerAtk].speed <= gBattleMons[battlerDef].speed)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerAtk].speed >= gBattleMons[battlerDef].speed) + ADJUST_SCORE(-10); + } + break; + case EFFECT_HEART_SWAP: + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + { + ADJUST_SCORE(-10); + } + else + { + u32 atkPositiveStages = CountPositiveStatStages(battlerAtk); + u32 atkNegativeStages = CountNegativeStatStages(battlerAtk); + u32 defPositiveStages = CountPositiveStatStages(battlerDef); + u32 defNegativeStages = CountNegativeStatStages(battlerDef); + + if (atkPositiveStages >= defPositiveStages && atkNegativeStages <= defNegativeStages) + ADJUST_SCORE(-10); + break; + } + break; + case EFFECT_POWER_SPLIT: + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + { + ADJUST_SCORE(-10); + } + else + { + u32 atkAttack = gBattleMons[battlerAtk].attack; + u32 defAttack = gBattleMons[battlerDef].attack; + u32 atkSpAttack = gBattleMons[battlerAtk].spAttack; + u32 defSpAttack = gBattleMons[battlerDef].spAttack; + + if (atkAttack + atkSpAttack >= defAttack + defSpAttack) // Combined attacker stats are > than combined target stats + ADJUST_SCORE(-10); + break; + } + break; + case EFFECT_GUARD_SPLIT: + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + { + ADJUST_SCORE(-10); + } + else + { + u32 atkDefense = gBattleMons[battlerAtk].defense; + u32 defDefense = gBattleMons[battlerDef].defense; + u32 atkSpDefense = gBattleMons[battlerAtk].spDefense; + u32 defSpDefense = gBattleMons[battlerDef].spDefense; + + if (atkDefense + atkSpDefense >= defDefense + defSpDefense) //Combined attacker stats are > than combined target stats + ADJUST_SCORE(-10); + break; + } + break; + case EFFECT_ME_FIRST: + if (predictedMove != MOVE_NONE) + { + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) + ADJUST_SCORE(-10); // Target is predicted to go first, Me First will fail + else + return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); + } + else + { + ADJUST_SCORE(-10); //Target is predicted to switch most likely + } + break; + case EFFECT_NATURAL_GIFT: + if (aiData->abilities[battlerAtk] == ABILITY_KLUTZ + || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM + || GetPocketByItemId(gBattleMons[battlerAtk].item) != POCKET_BERRY_POUCH) + ADJUST_SCORE(-10); + break; + case EFFECT_GRASSY_TERRAIN: + if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), aiData->partnerMove) || gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) + ADJUST_SCORE(-10); + break; + case EFFECT_ELECTRIC_TERRAIN: + if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), aiData->partnerMove) || gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + ADJUST_SCORE(-10); + break; + case EFFECT_PSYCHIC_TERRAIN: + if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), aiData->partnerMove) || gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + ADJUST_SCORE(-10); + break; + case EFFECT_MISTY_TERRAIN: + if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), aiData->partnerMove) || gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + ADJUST_SCORE(-10); + break; + case EFFECT_PLEDGE: + if (isDoubleBattle && gBattleMons[BATTLE_PARTNER(battlerAtk)].hp > 0) + { + if (aiData->partnerMove != MOVE_NONE + && gMovesInfo[aiData->partnerMove].effect == EFFECT_PLEDGE + && move != aiData->partnerMove) // Different pledge moves + { + if (gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) + // && gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 != 1) // Will wake up this turn - how would AI know + ADJUST_SCORE(-10); // Don't use combo move if your partner will cause failure + } + } + break; + case EFFECT_TRICK_ROOM: + if (PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_TRICK_ROOM)) + { + ADJUST_SCORE(-10); + } + else if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) + { + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM) // Trick Room Up + { + if (GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) // Attacker side slower than target side + ADJUST_SCORE(-10); // Keep the Trick Room up + } + else + { + if (GetBattlerSideSpeedAverage(battlerAtk) >= GetBattlerSideSpeedAverage(battlerDef)) // Attacker side faster than target side + ADJUST_SCORE(-10); // Keep the Trick Room down + } + } + break; + case EFFECT_MAGIC_ROOM: + if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_WONDER_ROOM: + if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_GRAVITY: + if ((gFieldStatuses & STATUS_FIELD_GRAVITY + && !IS_BATTLER_OF_TYPE(battlerAtk, TYPE_FLYING) + && aiData->holdEffects[battlerAtk] != HOLD_EFFECT_AIR_BALLOON) // Should revert Gravity in this case + || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_ION_DELUGE: + if (gFieldStatuses & STATUS_FIELD_ION_DELUGE + || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_FLING: + if (!CanFling(battlerAtk)) + { + ADJUST_SCORE(-10); + } + else + { + /* TODO Fling + u8 effect = gFlingTable[gBattleMons[battlerAtk].item].effect; + switch (effect) + { + case MOVE_EFFECT_BURN: + if (!AI_CanBurn(battlerAtk, battlerDef, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case MOVE_EFFECT_PARALYSIS: + if (!AI_CanParalyze(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case MOVE_EFFECT_POISON: + if (!AI_CanPoison(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case MOVE_EFFECT_TOXIC: + if (!AI_CanPoison(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case MOVE_EFFECT_FREEZE: + if (!CanBeFrozen(battlerDef, TRUE) + || MoveBlockedBySubstitute(move, battlerAtk, battlerDef)) + ADJUST_SCORE(-10); + break; + }*/ + } + break; + case EFFECT_EMBARGO: + if (aiData->abilities[battlerDef] == ABILITY_KLUTZ + || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM + || gDisableStructs[battlerDef].embargoTimer != 0 + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_POWDER: + if (!HasMoveWithType(battlerDef, TYPE_FIRE) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_TELEKINESIS: + if (gStatuses3[battlerDef] & (STATUS3_TELEKINESIS | STATUS3_ROOTED | STATUS3_SMACKED_DOWN) + || gFieldStatuses & STATUS_FIELD_GRAVITY + || aiData->holdEffects[battlerDef] == HOLD_EFFECT_IRON_BALL + || IsTelekinesisBannedSpecies(gBattleMons[battlerDef].species) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_HEAL_BLOCK: + if (gDisableStructs[battlerDef].healBlockTimer != 0 + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_SOAK: + if (PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove) + || (GetBattlerType(battlerDef, 0) == TYPE_WATER + && GetBattlerType(battlerDef, 1) == TYPE_WATER + && GetBattlerType(battlerDef, 2) == TYPE_MYSTERY)) + ADJUST_SCORE(-10); // target is already water-only + break; + case EFFECT_THIRD_TYPE: + switch (move) + { + case MOVE_TRICK_OR_TREAT: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case MOVE_FORESTS_CURSE: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + } + break; + case EFFECT_HEAL_PULSE: // and floral healing + if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef)) // Don't heal enemies + { + ADJUST_SCORE(-10); + break; + } + // fallthrough + case EFFECT_HIT_ENEMY_HEAL_ALLY: // pollen puff + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + { + if (gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK) + return 0; + if (AtMaxHp(battlerDef)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerDef].hp > gBattleMons[battlerDef].maxHP / 2) + ADJUST_SCORE(-5); + } + break; + case EFFECT_ELECTRIFY: + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER + //|| GetMoveTypeSpecial(battlerDef, predictedMove) == TYPE_ELECTRIC // Move will already be electric type + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_TOPSY_TURVY: + if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + { + u32 targetPositiveStages = CountPositiveStatStages(battlerDef); + u32 targetNegativeStages = CountNegativeStatStages(battlerDef); + + if (targetPositiveStages == 0 //No good stat changes to make bad + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + + else if (targetNegativeStages < targetPositiveStages) + ADJUST_SCORE(-5); //More stages would be made positive than negative + } + break; + case EFFECT_FAIRY_LOCK: + if ((gFieldStatuses & STATUS_FIELD_FAIRY_LOCK) || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_DO_NOTHING: + ADJUST_SCORE(-10); + break; + case EFFECT_INSTRUCT: + { + u16 instructedMove; + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) + instructedMove = predictedMove; + else + instructedMove = gLastMoves[battlerDef]; + + if (instructedMove == MOVE_NONE + || gMovesInfo[instructedMove].instructBanned + || MoveHasAdditionalEffectSelf(instructedMove, MOVE_EFFECT_RECHARGE) + // || IsZMove(instructedMove) // TODO: Z-move + || (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF) + || gBattleMons[battlerDef].status2 & STATUS2_MULTIPLETURNS + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + { + ADJUST_SCORE(-10); + } + else if (isDoubleBattle) + { + if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + ADJUST_SCORE(-10); + } + else + { + if (AI_GetBattlerMoveTargetType(battlerDef, instructedMove) & (MOVE_TARGET_SELECTED + | MOVE_TARGET_DEPENDS + | MOVE_TARGET_RANDOM + | MOVE_TARGET_BOTH + | MOVE_TARGET_FOES_AND_ALLY + | MOVE_TARGET_OPPONENTS_FIELD) + && instructedMove != MOVE_MIND_BLOWN && instructedMove != MOVE_STEEL_BEAM) + ADJUST_SCORE(-10); //Don't force the enemy to attack you again unless it can kill itself with Mind Blown + else if (instructedMove != MOVE_MIND_BLOWN) + ADJUST_SCORE(-5); //Do something better + } + } + break; + case EFFECT_QUASH: + if (!isDoubleBattle + || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_AFTER_YOU: + if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef) + || !isDoubleBattle + || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_SUCKER_PUNCH: + if (predictedMove != MOVE_NONE) + { + if (IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Opponent going first + ADJUST_SCORE(-10); + } + break; + case EFFECT_TAILWIND: + if (gSideTimers[GetBattlerSide(battlerAtk)].tailwindTimer != 0 + || PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_TAILWIND) + || (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1)) // Trick Room active and not ending this turn + ADJUST_SCORE(-10); + break; + case EFFECT_LUCKY_CHANT: + if (gSideTimers[GetBattlerSide(battlerAtk)].luckyChantTimer != 0 + || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + ADJUST_SCORE(-10); + break; + case EFFECT_MAGNET_RISE: + if (gFieldStatuses & STATUS_FIELD_GRAVITY + || gDisableStructs[battlerAtk].magnetRiseTimer != 0 + || aiData->holdEffects[battlerAtk] == HOLD_EFFECT_IRON_BALL + || gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_MAGNET_RISE | STATUS3_SMACKED_DOWN) + || !IsBattlerGrounded(battlerAtk)) + ADJUST_SCORE(-10); + break; + case EFFECT_CAMOUFLAGE: + if (!CanCamouflage(battlerAtk)) + ADJUST_SCORE(-10); + break; + case EFFECT_SYNCHRONOISE: + //Check holding ring target or is of same type + if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_RING_TARGET + || IS_BATTLER_OF_TYPE(battlerDef, GetBattlerType(battlerAtk, 0)) + || IS_BATTLER_OF_TYPE(battlerDef, GetBattlerType(battlerAtk, 1)) + || IS_BATTLER_OF_TYPE(battlerDef, GetBattlerType(battlerAtk, 2))) + break; + else + ADJUST_SCORE(-10); + break; + case EFFECT_ERUPTION: + if (effectiveness <= AI_EFFECTIVENESS_x0_5) + ADJUST_SCORE(-1); + if (aiData->hpPercents[battlerDef] < 50) + ADJUST_SCORE(-1); + break; + case EFFECT_FLAIL: + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER // Opponent should go first + || aiData->hpPercents[battlerAtk] > 50) + ADJUST_SCORE(-4); + break; + //TODO + //case EFFECT_PLASMA_FISTS: + //break; + //case EFFECT_SHELL_TRAP: + //break; + //case EFFECT_BEAK_BLAST: + //break; + case EFFECT_SKY_DROP: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING)) + ADJUST_SCORE(-10); + if (BattlerWillFaintFromWeather(battlerAtk, aiData->abilities[battlerAtk]) + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || GetBattlerWeight(battlerDef) >= 2000) //200.0 kg + ADJUST_SCORE(-10); + break; + /*case EFFECT_NO_RETREAT: + if (TrappedByNoRetreat(battlerAtk)) + ADJUST_SCORE(-10); + break; + case EFFECT_EXTREME_EVOBOOST: + if (MainStatsMaxed(battlerAtk)) + ADJUST_SCORE(-10); + break; + case EFFECT_CLANGOROUS_SOUL: + if (gBattleMons[battlerAtk].hp <= gBattleMons[battlerAtk].maxHP / 3) + ADJUST_SCORE(-10); + break;*/ + case EFFECT_REVIVAL_BLESSING: + if (GetFirstFaintedPartyIndex(battlerAtk) == PARTY_SIZE) + ADJUST_SCORE(-10); + else if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + ADJUST_SCORE(-10); + else if (CanTargetFaintAi(battlerDef, battlerAtk) + && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) + ADJUST_SCORE(-10); + break; + case EFFECT_JUNGLE_HEALING: + if (AtMaxHp(battlerAtk) + && AtMaxHp(BATTLE_PARTNER(battlerAtk)) + && !(gBattleMons[battlerAtk].status1 & STATUS1_ANY) + && !(gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 & STATUS1_ANY)) + ADJUST_SCORE(-10); + break; + case EFFECT_TAKE_HEART: + if ((!(gBattleMons[battlerAtk].status1 & STATUS1_ANY) + || PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_JUNGLE_HEALING) + || PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_HEAL_BELL) + || PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_AROMATHERAPY)) + && !BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK) + && !BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) + ADJUST_SCORE(-10); + break; + case EFFECT_UPPER_HAND: + if (predictedMove == MOVE_NONE || IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER || GetMovePriority(battlerDef, move) < 1 || GetMovePriority(battlerDef, move) > 3) // Opponent going first or not using priority move + ADJUST_SCORE(-10); + break; + case EFFECT_PLACEHOLDER: + return 0; // cannot even select + } // move effect checks + + if (score < 0) + score = 0; + + return score; +} + +static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex; + + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + return score; + + if (gMovesInfo[move].power == 0) + return score; // can't make anything faint with no power + + if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, movesetIndex, 0) && gMovesInfo[move].effect != EFFECT_EXPLOSION) + { + if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) + ADJUST_SCORE(FAST_KILL); + else + ADJUST_SCORE(SLOW_KILL); + } + else if (CanTargetFaintAi(battlerDef, battlerAtk) + && GetWhichBattlerFaster(battlerAtk, battlerDef, TRUE) != AI_IS_FASTER + && GetMovePriority(battlerAtk, move) > 0) + { + ADJUST_SCORE(LAST_CHANCE); + } + + return score; +} + +// double battle logic +static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + // move data + u32 moveType = gMovesInfo[move].type; + u32 effect = gMovesInfo[move].effect; + u32 moveTarget = AI_GetBattlerMoveTargetType(battlerAtk, move); + // ally data + u32 battlerAtkPartner = BATTLE_PARTNER(battlerAtk); + struct AiLogicData *aiData = AI_DATA; + u32 atkPartnerAbility = aiData->abilities[BATTLE_PARTNER(battlerAtk)]; + u32 atkPartnerHoldEffect = aiData->holdEffects[BATTLE_PARTNER(battlerAtk)]; + bool32 partnerProtecting = (gMovesInfo[aiData->partnerMove].effect == EFFECT_PROTECT); + bool32 attackerHasBadAbility = (gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating < 0); + bool32 partnerHasBadAbility = (gAbilitiesInfo[atkPartnerAbility].aiRating < 0); + u32 predictedMove = aiData->predictedMoves[battlerDef]; + + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + + // check what effect partner is using + if (aiData->partnerMove != 0) + { + switch (gMovesInfo[aiData->partnerMove].effect) + { + case EFFECT_HELPING_HAND: + if (IS_MOVE_STATUS(move)) + ADJUST_SCORE(-7); + break; + case EFFECT_PERISH_SONG: + if (!(gBattleMons[battlerDef].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED))) + { + if (IsTrappingMove(aiData->partnerMove) || predictedMove == MOVE_INGRAIN) + ADJUST_SCORE(WEAK_EFFECT); + } + break; + // Don't change weather if ally already decided to do so. + case EFFECT_SUNNY_DAY: + case EFFECT_HAIL: + case EFFECT_SNOWSCAPE: + case EFFECT_RAIN_DANCE: + case EFFECT_SANDSTORM: + if (IsMoveEffectWeather(move)) + ADJUST_SCORE(-10); + break; + } + } // check partner move effect + + // Adjust for always crit moves + if (gMovesInfo[aiData->partnerMove].alwaysCriticalHit && aiData->abilities[battlerAtk] == ABILITY_ANGER_POINT) + { + if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_SLOWER) // Partner moving first + { + // discourage raising our attack since it's about to be maxed out + if (IsAttackBoostMoveEffect(effect)) + ADJUST_SCORE(-3); + // encourage moves hitting multiple opponents + if (!IS_MOVE_STATUS(move) && (moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) + ADJUST_SCORE(GOOD_EFFECT); + } + } + + // consider our move effect relative to partner state + switch (effect) + { + case EFFECT_HELPING_HAND: + if (!IsBattlerAlive(battlerAtkPartner) || !HasDamagingMove(battlerAtkPartner)) + ADJUST_SCORE(-5); + break; + case EFFECT_PERISH_SONG: + if (aiData->partnerMove != 0 && HasTrappingMoveEffect(battlerAtkPartner)) + ADJUST_SCORE(WEAK_EFFECT); + break; + case EFFECT_MAGNET_RISE: + if (IsBattlerGrounded(battlerAtk) + && (HasMove(battlerAtkPartner, MOVE_EARTHQUAKE) || HasMove(battlerAtkPartner, MOVE_MAGNITUDE)) + && (AI_GetMoveEffectiveness(MOVE_EARTHQUAKE, battlerAtk, battlerAtkPartner) != AI_EFFECTIVENESS_x0)) // Doesn't resist ground move + { + RETURN_SCORE_PLUS(DECENT_EFFECT); // partner has earthquake or magnitude -> good idea to use magnet rise + } + break; + case EFFECT_DRAGON_CHEER: + if (gBattleMons[battlerAtkPartner].status2 & STATUS2_FOCUS_ENERGY_ANY || !HasDamagingMove(battlerAtkPartner)) + ADJUST_SCORE(-5); + else if (atkPartnerHoldEffect == HOLD_EFFECT_SCOPE_LENS + || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_DRAGON) + || gMovesInfo[aiData->partnerMove].criticalHitStage > 0 + || HasMoveWithCriticalHitChance(battlerAtkPartner)) + ADJUST_SCORE(GOOD_EFFECT); + } // our effect relative to partner + + // consider global move effects + switch (effect) + { + case EFFECT_SANDSTORM: + if (ShouldSetSandstorm(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); // our partner benefits from sandstorm + } + break; + case EFFECT_RAIN_DANCE: + if (ShouldSetRain(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); // our partner benefits from rain + } + break; + case EFFECT_SUNNY_DAY: + if (ShouldSetSun(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); // our partner benefits from sun + } + break; + case EFFECT_HAIL: + if (IsBattlerAlive(battlerAtkPartner) + && ShouldSetHail(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(DECENT_EFFECT); // our partner benefits from hail + } + break; + case EFFECT_SNOWSCAPE: + if (IsBattlerAlive(battlerAtkPartner) + && ShouldSetSnow(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(DECENT_EFFECT); // our partner benefits from snow + } + break; + } // global move effect check + + // check specific target + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + { + // partner ability checks + if (!partnerProtecting && moveTarget != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move)) + { + switch (atkPartnerAbility) + { + case ABILITY_VOLT_ABSORB: + if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE)) + { + RETURN_SCORE_MINUS(10); + } + break; // handled in AI_HPAware + case ABILITY_MOTOR_DRIVE: + if (moveType == TYPE_ELECTRIC && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case ABILITY_LIGHTNING_ROD: + if (moveType == TYPE_ELECTRIC + && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_SPECIAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case ABILITY_WATER_ABSORB: + case ABILITY_DRY_SKIN: + case ABILITY_EARTH_EATER: + if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE)) + { + RETURN_SCORE_MINUS(10); + } + break; // handled in AI_HPAware + case ABILITY_STORM_DRAIN: + if (moveType == TYPE_WATER + && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_SPECIAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case ABILITY_WATER_COMPACTION: + if (moveType == TYPE_WATER && GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) >= 4) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); // only mon with this ability is weak to water so only make it okay if we do very little damage + } + RETURN_SCORE_MINUS(10); + break; + case ABILITY_FLASH_FIRE: + if (moveType == TYPE_FIRE + && HasMoveWithType(battlerAtkPartner, TYPE_FIRE) + && !(gBattleResources->flags->flags[battlerAtkPartner] & RESOURCE_FLAG_FLASH_FIRE)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case ABILITY_SAP_SIPPER: + if (moveType == TYPE_GRASS + && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case ABILITY_JUSTIFIED: + if (moveType == TYPE_DARK + && !IS_MOVE_STATUS(move) + && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case ABILITY_RATTLED: + if (!IS_MOVE_STATUS(move) + && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case ABILITY_CONTRARY: + if (IsStatLoweringEffect(effect)) + { + RETURN_SCORE_PLUS(DECENT_EFFECT); + } + break; + case ABILITY_DEFIANT: + if (IsStatLoweringEffect(effect) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case ABILITY_COMPETITIVE: + if (IsStatLoweringEffect(effect) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + } + } // ability checks + + // attacker move effects specifically targeting partner + if (!partnerProtecting) + { + switch (effect) + { + case EFFECT_PURIFY: + if (gBattleMons[battlerAtkPartner].status1 & STATUS1_ANY) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case EFFECT_SWAGGER: + if (gBattleMons[battlerAtkPartner].statStages[STAT_ATK] < MAX_STAT_STAGE + && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL) + && (!AI_CanBeConfused(battlerAtk, battlerAtkPartner, move, TRUE) + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case EFFECT_FLATTER: + if (gBattleMons[battlerAtkPartner].statStages[STAT_SPATK] < MAX_STAT_STAGE + && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_SPECIAL) + && (!AI_CanBeConfused(battlerAtk, battlerAtkPartner, move, TRUE) + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case EFFECT_BEAT_UP: + if (atkPartnerAbility == ABILITY_JUSTIFIED + && moveType == TYPE_DARK + && !IS_MOVE_STATUS(move) + && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case EFFECT_SKILL_SWAP: + if (aiData->abilities[battlerAtk] != aiData->abilities[BATTLE_PARTNER(battlerAtk)] && !attackerHasBadAbility) + { + if (aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_TRUANT) + { + RETURN_SCORE_PLUS(10); + } + else if (aiData->abilities[battlerAtk] == ABILITY_COMPOUND_EYES + && HasMoveWithLowAccuracy(battlerAtkPartner, FOE(battlerAtkPartner), 90, TRUE, atkPartnerAbility, aiData->abilities[FOE(battlerAtkPartner)], atkPartnerHoldEffect, aiData->holdEffects[FOE(battlerAtkPartner)])) + { + RETURN_SCORE_PLUS(3); + } + } + break; + case EFFECT_ROLE_PLAY: + if (attackerHasBadAbility && !partnerHasBadAbility) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case EFFECT_WORRY_SEED: + case EFFECT_GASTRO_ACID: + case EFFECT_SIMPLE_BEAM: + if (partnerHasBadAbility) + { + RETURN_SCORE_PLUS(DECENT_EFFECT); + } + break; + case EFFECT_ENTRAINMENT: + if (partnerHasBadAbility && IsAbilityOfRating(aiData->abilities[battlerAtk], 0)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case EFFECT_SOAK: + if (atkPartnerAbility == ABILITY_WONDER_GUARD + && (GetBattlerType(battlerAtkPartner, 0) != TYPE_WATER + || GetBattlerType(battlerAtkPartner, 1) != TYPE_WATER + || GetBattlerType(battlerAtkPartner, 2) != TYPE_WATER)) + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case EFFECT_INSTRUCT: + { + u16 instructedMove; + if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_FASTER) + instructedMove = aiData->partnerMove; + else + instructedMove = gLastMoves[battlerAtkPartner]; + + if (instructedMove != MOVE_NONE + && !IS_MOVE_STATUS(instructedMove) + && (AI_GetBattlerMoveTargetType(battlerAtkPartner, instructedMove) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) // Use instruct on multi-target moves + { + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + } + break; + case EFFECT_AFTER_YOU: + if (AI_WhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), aiData->partnerMove) == AI_IS_SLOWER // Opponent mon 1 goes before partner + || AI_WhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), aiData->partnerMove) == AI_IS_SLOWER) // Opponent mon 2 goes before partner + { + if (gMovesInfo[aiData->partnerMove].effect == EFFECT_COUNTER || gMovesInfo[aiData->partnerMove].effect == EFFECT_MIRROR_COAT) + break; // These moves need to go last + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; + case EFFECT_HEAL_PULSE: + case EFFECT_HIT_ENEMY_HEAL_ALLY: + if (AI_WhoStrikesFirst(battlerAtk, FOE(battlerAtk), move) == AI_IS_FASTER + && AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(FOE(battlerAtk)), move) == AI_IS_FASTER + && gBattleMons[battlerAtkPartner].hp < gBattleMons[battlerAtkPartner].maxHP / 2) + RETURN_SCORE_PLUS(WEAK_EFFECT); + break; + } // attacker move effects + } // check partner protecting + + ADJUST_SCORE(-30); // otherwise, don't target partner + } + else // checking opponent + { + // these checks mostly handled in AI_CheckBadMove and AI_CheckViability + switch (effect) + { + case EFFECT_SKILL_SWAP: + if (aiData->abilities[battlerAtk] == ABILITY_TRUANT) + ADJUST_SCORE(GOOD_EFFECT); + else if (IsAbilityOfRating(aiData->abilities[battlerAtk], 0) || IsAbilityOfRating(aiData->abilities[battlerDef], 10)) + ADJUST_SCORE(DECENT_EFFECT); // we want to transfer our bad ability or take their awesome ability + break; + case EFFECT_EARTHQUAKE: + case EFFECT_MAGNITUDE: + if (!IsBattlerGrounded(battlerAtkPartner) + || (IsBattlerGrounded(battlerAtkPartner) + && AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_SLOWER + && IsUngroundingEffect(gMovesInfo[aiData->partnerMove].effect))) + ADJUST_SCORE(DECENT_EFFECT); + else if (IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_FIRE) + || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_ELECTRIC) + || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_POISON) + || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_ROCK)) + ADJUST_SCORE(-10); // partner will be hit by earthquake and is weak to it + else if (IsBattlerAlive(battlerAtkPartner)) + ADJUST_SCORE(-3); + break; + } + + // lightning rod, flash fire against enemy handled in AI_CheckBadMove + } + + return score; +} + +static bool32 IsPinchBerryItemEffect(u32 holdEffect) +{ + switch (holdEffect) + { + case HOLD_EFFECT_ATTACK_UP: + case HOLD_EFFECT_DEFENSE_UP: + case HOLD_EFFECT_SPEED_UP: + case HOLD_EFFECT_SP_ATTACK_UP: + case HOLD_EFFECT_SP_DEFENSE_UP: + case HOLD_EFFECT_CRITICAL_UP: + case HOLD_EFFECT_RANDOM_STAT_UP: + case HOLD_EFFECT_CUSTAP_BERRY: + case HOLD_EFFECT_MICLE_BERRY: + return TRUE; + } + + return FALSE; +} + +static s32 CompareMoveAccuracies(u32 battlerAtk, u32 battlerDef, u32 moveSlot1, u32 moveSlot2) +{ + u32 acc1 = AI_DATA->moveAccuracy[battlerAtk][battlerDef][moveSlot1]; + u32 acc2 = AI_DATA->moveAccuracy[battlerAtk][battlerDef][moveSlot2]; + + if (acc1 > acc2) + return 1; + else if (acc2 > acc1) + return -1; + return 0; +} + +static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId) +{ + u32 i; + bool32 multipleBestMoves = FALSE; + s32 viableMoveScores[MAX_MON_MOVES]; + s32 bestViableMoveScore; + s32 noOfHits[MAX_MON_MOVES]; + s32 score = 0; + s32 leastHits = 1000; + u16 *moves = GetMovesArray(battlerAtk); + bool8 isTwoTurnNotSemiInvulnerableMove[MAX_MON_MOVES]; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && gMovesInfo[moves[i]].power) + { + noOfHits[i] = GetNoOfHitsToKOBattler(battlerAtk, battlerDef, i); + if (noOfHits[i] < leastHits && noOfHits[i] != 0) + { + leastHits = noOfHits[i]; + } + viableMoveScores[i] = AI_SCORE_DEFAULT; + isTwoTurnNotSemiInvulnerableMove[i] = IsTwoTurnNotSemiInvulnerableMove(battlerAtk, moves[i]); + } + else + { + noOfHits[i] = -1; + viableMoveScores[i] = 0; + isTwoTurnNotSemiInvulnerableMove[i] = FALSE; + } + /* + MgbaPrintf_("%S: required hits: %d Dmg: %d", gMoveNames[moves[i]], noOfHits[i], AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]); + */ + } + + // Priority list: + // 1. Less no of hits to ko + // 2. Not charging + // 3. More accuracy + // 4. Better effect + + // Current move requires the least hits to KO. Compare with other moves. + if (leastHits == noOfHits[currId]) + { + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (i == currId) + continue; + if (noOfHits[currId] == noOfHits[i]) + { + multipleBestMoves = TRUE; + // We need to make sure it's the current move which is objectively better. + if (isTwoTurnNotSemiInvulnerableMove[i] && !isTwoTurnNotSemiInvulnerableMove[currId]) + viableMoveScores[i] -= 3; + else if (!isTwoTurnNotSemiInvulnerableMove[i] && isTwoTurnNotSemiInvulnerableMove[currId]) + viableMoveScores[currId] -= 3; + + switch (CompareMoveAccuracies(battlerAtk, battlerDef, currId, i)) + { + case 1: + viableMoveScores[i] -= 2; + break; + case -1: + viableMoveScores[currId] -= 2; + break; + } + switch (AI_WhichMoveBetter(moves[currId], moves[i], battlerAtk, battlerDef, noOfHits[currId])) + { + case 1: + viableMoveScores[i] -= 1; + break; + case -1: + viableMoveScores[currId] -= 1; + break; + } + } + } + // Turns out the current move deals the most dmg compared to the other 3. + if (!multipleBestMoves) + ADJUST_SCORE(BEST_DAMAGE_MOVE); + else + { + bestViableMoveScore = 0; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (viableMoveScores[i] > bestViableMoveScore) + bestViableMoveScore = viableMoveScores[i]; + } + // Unless a better move was found increase score of current move + if (viableMoveScores[currId] == bestViableMoveScore) + ADJUST_SCORE(BEST_DAMAGE_MOVE); + } + } + + return score; +} + +static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) +{ + // move data + u32 moveEffect = gMovesInfo[move].effect; + struct AiLogicData *aiData = AI_DATA; + u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex; + u32 effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex]; + + s32 score = 0; + u32 predictedMove = aiData->predictedMoves[battlerDef]; + u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove); + bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); + u32 i; + + // The AI should understand that while Dynamaxed, status moves function like Protect. + if (IsDynamaxed(battlerAtk) && gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS) + moveEffect = EFFECT_PROTECT; + + // check status move preference + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IS_MOVE_STATUS(move) && effectiveness != AI_EFFECTIVENESS_x0) + ADJUST_SCORE(10); + + // check thawing moves + if ((gBattleMons[battlerAtk].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE)) && gMovesInfo[move].thawsUser) + ADJUST_SCORE(10); + + // check burn / frostbite + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && AI_DATA->abilities[battlerAtk] == ABILITY_NATURAL_CURE) + { + if ((gBattleMons[battlerAtk].status1 & STATUS1_BURN && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL, TRUE)) + || (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL, TRUE))) + ADJUST_SCORE(-20); // Force switch if all your attacking moves are physical and you have Natural Cure. + } + + // move effect checks + switch (moveEffect) + { + case EFFECT_SLEEP: + case EFFECT_YAWN: + IncreaseSleepScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_ABSORB: + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_BIG_ROOT && effectiveness >= AI_EFFECTIVENESS_x1) + ADJUST_SCORE(DECENT_EFFECT); + case EFFECT_EXPLOSION: + case EFFECT_MEMENTO: + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7) + { + if (aiData->hpPercents[battlerAtk] < 50 && AI_RandLessThan(128)) + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_MIRROR_MOVE: + if (predictedMove != MOVE_NONE) + return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score); + break; + case EFFECT_ATTACK_UP: + case EFFECT_ATTACK_UP_USER_ALLY: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score); + break; + case EFFECT_ATTACK_UP_2: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK_2, &score); + break; + case EFFECT_DEFENSE_UP: + case EFFECT_DEFENSE_UP_3: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score); + break; + case EFFECT_DEFENSE_UP_2: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF_2, &score); + break; + case EFFECT_SPEED_UP: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score); + break; + case EFFECT_SPEED_UP_2: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED_2, &score); + break; + case EFFECT_SPECIAL_ATTACK_UP: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK, &score); + break; + case EFFECT_SPECIAL_ATTACK_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_3: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK_2, &score); + break; + case EFFECT_SPECIAL_DEFENSE_UP: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score); + break; + case EFFECT_SPECIAL_DEFENSE_UP_2: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF_2, &score); + break; + case EFFECT_ACCURACY_UP: + case EFFECT_ACCURACY_UP_2: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ACC, &score); + break; + case EFFECT_EVASION_UP: + case EFFECT_EVASION_UP_2: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_EVASION, &score); + break; + case EFFECT_ATTACK_DOWN: + case EFFECT_ATTACK_DOWN_2: + if (!ShouldLowerAttack(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(-2); + if (gBattleMons[battlerDef].statStages[STAT_ATK] < DEFAULT_STAT_STAGE) + ADJUST_SCORE(-1); + else if (aiData->hpPercents[battlerAtk] <= 90) + ADJUST_SCORE(-1); + if (gBattleMons[battlerDef].statStages[STAT_ATK] > 3 && !AI_RandLessThan(50)) + ADJUST_SCORE(-2); + else if (aiData->hpPercents[battlerDef] < 70) + ADJUST_SCORE(-2); + break; + case EFFECT_DEFENSE_DOWN: + case EFFECT_DEFENSE_DOWN_2: + if (!ShouldLowerDefense(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(-2); + if ((aiData->hpPercents[battlerAtk] < 70 && !AI_RandLessThan(50)) || (gBattleMons[battlerDef].statStages[STAT_DEF] <= 3 && !AI_RandLessThan(50))) + ADJUST_SCORE(-2); + if (aiData->hpPercents[battlerDef] <= 70) + ADJUST_SCORE(-2); + break; + case EFFECT_SPEED_DOWN: + case EFFECT_SPEED_DOWN_2: + if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) + ADJUST_SCORE(-3); + else if (!AI_RandLessThan(70)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_SPECIAL_ATTACK_DOWN: + case EFFECT_SPECIAL_ATTACK_DOWN_2: + if (!ShouldLowerSpAtk(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(-2); + if (gBattleMons[battlerDef].statStages[STAT_SPATK] < DEFAULT_STAT_STAGE) + ADJUST_SCORE(-1); + else if (aiData->hpPercents[battlerAtk] <= 90) + ADJUST_SCORE(-1); + if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 3 && !AI_RandLessThan(50)) + ADJUST_SCORE(-2); + else if (aiData->hpPercents[battlerDef] < 70) + ADJUST_SCORE(-2); + break; + case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN_2: + if (!ShouldLowerSpDef(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(-2); + if ((aiData->hpPercents[battlerAtk] < 70 && !AI_RandLessThan(50)) + || (gBattleMons[battlerDef].statStages[STAT_SPDEF] <= 3 && !AI_RandLessThan(50))) + ADJUST_SCORE(-2); + if (aiData->hpPercents[battlerDef] <= 70) + ADJUST_SCORE(-2); + break; + case EFFECT_ACCURACY_DOWN: + case EFFECT_ACCURACY_DOWN_2: + if (ShouldLowerAccuracy(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(-2); + if ((aiData->hpPercents[battlerAtk] < 70 || aiData->hpPercents[battlerDef] < 70) && AI_RandLessThan(100)) + ADJUST_SCORE(-1); + if (gBattleMons[battlerDef].statStages[STAT_ACC] <= 4 && !AI_RandLessThan(80)) + ADJUST_SCORE(-2); + if (gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY && !AI_RandLessThan(70)) + ADJUST_SCORE(DECENT_EFFECT); + if (gStatuses3[battlerDef] & STATUS3_LEECHSEED && !AI_RandLessThan(70)) + ADJUST_SCORE(DECENT_EFFECT); + if (gStatuses3[battlerDef] & STATUS3_ROOTED && AI_RandLessThan(128)) + ADJUST_SCORE(WEAK_EFFECT); + if (gBattleMons[battlerDef].status2 & STATUS2_CURSED && !AI_RandLessThan(70)) + ADJUST_SCORE(DECENT_EFFECT); + if (aiData->hpPercents[battlerAtk] > 70 || gBattleMons[battlerDef].statStages[STAT_ACC] < DEFAULT_STAT_STAGE) + break; + else if (aiData->hpPercents[battlerAtk] < 40 || aiData->hpPercents[battlerDef] < 40 || !AI_RandLessThan(70)) + ADJUST_SCORE(-2); + break; + case EFFECT_EVASION_DOWN: + case EFFECT_EVASION_DOWN_2: + if (!ShouldLowerEvasion(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(-2); + if ((aiData->hpPercents[battlerAtk] < 70 || gBattleMons[battlerDef].statStages[STAT_EVASION] <= 3) && !AI_RandLessThan(50)) + ADJUST_SCORE(-2); + if (aiData->hpPercents[battlerDef] <= 70) + ADJUST_SCORE(-2); + if (gBattleMons[battlerAtk].statStages[STAT_ACC] < DEFAULT_STAT_STAGE) + ADJUST_SCORE(WEAK_EFFECT); + if (gBattleMons[battlerDef].statStages[STAT_EVASION] < 7 || aiData->abilities[battlerAtk] == ABILITY_NO_GUARD) + ADJUST_SCORE(-2); + break; + case EFFECT_BIDE: + if (aiData->hpPercents[battlerAtk] < 90) + ADJUST_SCORE(-2); // Should be either removed or turned into increasing score + case EFFECT_ACUPRESSURE: + break; + case EFFECT_ATTACK_ACCURACY_UP: // hone claws + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ACC, &score); + break; + case EFFECT_GROWTH: + case EFFECT_ATTACK_SPATK_UP: // work up + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK, &score); + break; + case EFFECT_HAZE: + if (AnyStatIsRaised(BATTLE_PARTNER(battlerAtk)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) + break; + score += AI_TryToClearStats(battlerAtk, battlerDef, isDoubleBattle); + break; + case EFFECT_ROAR: + if ((gMovesInfo[move].soundMove && aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF) || aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS) + break; + score += AI_TryToClearStats(battlerAtk, battlerDef, isDoubleBattle); + break; + case EFFECT_MULTI_HIT: + case EFFECT_TRIPLE_KICK: + if (AI_MoveMakesContact(aiData->abilities[battlerAtk], aiData->holdEffects[battlerAtk], move) + && aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD + && aiData->holdEffects[battlerDef] == HOLD_EFFECT_ROCKY_HELMET) + ADJUST_SCORE(-2); + break; + case EFFECT_CONVERSION: + if (!IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[gBattleMons[battlerAtk].moves[0]].type)) + ADJUST_SCORE(WEAK_EFFECT); + break; + case EFFECT_SWALLOW: + if (gDisableStructs[battlerAtk].stockpileCounter == 0) + { + break; + } + else + { + u32 healPercent = 0; + switch (gDisableStructs[battlerAtk].stockpileCounter) + { + case 1: + healPercent = 25; + break; + case 2: + healPercent = 50; + break; + case 3: + healPercent = 100; + break; + default: + break; + } + + if (ShouldRecover(battlerAtk, battlerDef, move, healPercent)) + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_RESTORE_HP: + case EFFECT_SOFTBOILED: + case EFFECT_ROOST: + case EFFECT_MORNING_SUN: + case EFFECT_SYNTHESIS: + case EFFECT_MOONLIGHT: + if (ShouldRecover(battlerAtk, battlerDef, move, 50)) + ADJUST_SCORE(GOOD_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_BIG_ROOT) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_TOXIC: + case EFFECT_POISON: + IncreasePoisonScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_LIGHT_SCREEN: + case EFFECT_REFLECT: + case EFFECT_AURORA_VEIL: + if (ShouldSetScreen(battlerAtk, battlerDef, moveEffect)) + { + ADJUST_SCORE(BEST_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_LIGHT_CLAY) + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_REST: + if (!(AI_CanSleep(battlerAtk, aiData->abilities[battlerAtk]))) + { + break; + } + else if (ShouldRecover(battlerAtk, battlerDef, move, 100)) + { + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_CURE_SLP + || aiData->holdEffects[battlerAtk] == HOLD_EFFECT_CURE_STATUS + || HasMoveEffect(EFFECT_SLEEP_TALK, battlerAtk) + || HasMoveEffect(EFFECT_SNORE, battlerAtk) + || aiData->abilities[battlerAtk] == ABILITY_SHED_SKIN + || aiData->abilities[battlerAtk] == ABILITY_EARLY_BIRD + || (AI_GetWeather(aiData) & B_WEATHER_RAIN && gWishFutureKnock.weatherDuration != 1 && aiData->abilities[battlerAtk] == ABILITY_HYDRATION && aiData->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA)) + ADJUST_SCORE(GOOD_EFFECT); + } + break; + case EFFECT_OHKO: + if (gStatuses3[battlerAtk] & STATUS3_ALWAYS_HITS) + ADJUST_SCORE(BEST_EFFECT); + break; + case EFFECT_MEAN_LOOK: + if (ShouldTrap(battlerAtk, battlerDef, move)) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_FOCUS_ENERGY: + case EFFECT_LASER_FOCUS: + if (aiData->abilities[battlerAtk] == ABILITY_SUPER_LUCK + || aiData->abilities[battlerAtk] == ABILITY_SNIPER + || aiData->holdEffects[battlerAtk] == HOLD_EFFECT_SCOPE_LENS + || HasHighCritRatioMove(battlerAtk)) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_CONFUSE: + IncreaseConfusionScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_PARALYZE: + IncreaseParalyzeScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_SUBSTITUTE: + ADJUST_SCORE(GOOD_EFFECT); + if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) + ADJUST_SCORE(GOOD_EFFECT); + if (gBattleMons[battlerDef].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_FROSTBITE)) + ADJUST_SCORE(DECENT_EFFECT); + if (HasMoveEffect(battlerDef, EFFECT_SLEEP) + || HasMoveEffect(battlerDef, EFFECT_TOXIC) + || HasMoveEffect(battlerDef, EFFECT_POISON) + || HasMoveEffect(battlerDef, EFFECT_PARALYZE) + || HasMoveEffect(battlerDef, EFFECT_WILL_O_WISP) + || HasMoveEffect(battlerDef, EFFECT_CONFUSE) + || HasMoveEffect(battlerDef, EFFECT_LEECH_SEED)) + ADJUST_SCORE(GOOD_EFFECT); + if (!gBattleMons[battlerDef].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION && aiData->hpPercents[battlerAtk] > 70)) + ADJUST_SCORE(WEAK_EFFECT); + break; + case EFFECT_MIMIC: + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) + { + if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF) + return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score); + } + break; + case EFFECT_LEECH_SEED: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) + || gStatuses3[battlerDef] & STATUS3_LEECHSEED + || HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) + || aiData->abilities[battlerDef] == ABILITY_LIQUID_OOZE + || aiData->abilities[battlerDef] == ABILITY_MAGIC_GUARD) + break; + ADJUST_SCORE(GOOD_EFFECT); + if (!HasDamagingMove(battlerDef) || IsBattlerTrapped(battlerDef, FALSE)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_DO_NOTHING: + //todo - check z splash, z celebrate, z happy hour (lol) + break; + case EFFECT_TELEPORT: // Either remove or add better logic + if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) || GetBattlerSide(battlerAtk) != B_SIDE_PLAYER) + break; + //fallthrough + case EFFECT_HIT_ESCAPE: + case EFFECT_PARTING_SHOT: + if (!IsDoubleBattle()) + { + switch (ShouldPivot(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, movesetIndex)) + { + case 0: // no + ADJUST_SCORE(-10); // technically should go in CheckBadMove, but this is easier/less computationally demanding + break; + case 1: // maybe + break; + case 2: // yes + ADJUST_SCORE(BEST_EFFECT); + break; + } + } + else //Double Battle + { + if (CountUsablePartyMons(battlerAtk) == 0) + break; // Can't switch + + //if (switchAbility == ABILITY_INTIMIDATE && PartyHasMoveCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + //ADJUST_SCORE(7); + } + break; + case EFFECT_BATON_PASS: + if (ShouldSwitch(battlerAtk, FALSE) && (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE + || (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING | STATUS3_MAGNET_RISE | STATUS3_POWER_TRICK)) + || AnyStatIsRaised(battlerAtk))) + ADJUST_SCORE(BEST_EFFECT); + break; + case EFFECT_DISABLE: + if (gDisableStructs[battlerDef].disableTimer == 0 + && (gLastMoves[battlerDef] != MOVE_NONE) + && (gLastMoves[battlerDef] != 0xFFFF) + && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) + && (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)) + { + if (CanTargetMoveFaintAi(gLastMoves[battlerDef], battlerDef, battlerAtk, 1)) + ADJUST_SCORE(GOOD_EFFECT); // Disable move that can kill attacker + } + break; + case EFFECT_ENCORE: + if (gDisableStructs[battlerDef].encoreTimer == 0 + && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) + && (gBattleMoveEffects[gMovesInfo[gLastMoves[battlerDef]].effect].encourageEncore)) + ADJUST_SCORE(BEST_EFFECT); + break; + case EFFECT_SLEEP_TALK: + case EFFECT_SNORE: + if (!IsWakeupTurn(battlerAtk) && gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) + ADJUST_SCORE(BEST_EFFECT); + break; + case EFFECT_LOCK_ON: + if (HasMoveEffect(battlerAtk, EFFECT_OHKO)) + ADJUST_SCORE(GOOD_EFFECT); + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 85, TRUE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef])) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_DESTINY_BOND: + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && CanTargetFaintAi(battlerDef, battlerAtk)) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_SPITE: + //TODO - predicted move + break; + case EFFECT_WISH: + case EFFECT_HEAL_BELL: + if (ShouldUseWishAromatherapy(battlerAtk, battlerDef, move)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_CURSE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) + { + if (IsBattlerTrapped(battlerDef, TRUE)) + ADJUST_SCORE(GOOD_EFFECT); + else + ADJUST_SCORE(WEAK_EFFECT); + } + else if (aiData->abilities[battlerAtk] != ABILITY_CONTRARY) + { + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score); + } + break; + case EFFECT_PROTECT: + if (predictedMove == 0xFFFF) + predictedMove = MOVE_NONE; + switch (move) + { + case MOVE_QUICK_GUARD: + if (predictedMove != MOVE_NONE && gMovesInfo[predictedMove].priority > 0) + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + break; + case MOVE_WIDE_GUARD: + if (predictedMove != MOVE_NONE && AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH)) + { + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + } + else if (isDoubleBattle && AI_GetBattlerMoveTargetType(BATTLE_PARTNER(battlerAtk), aiData->partnerMove) & MOVE_TARGET_FOES_AND_ALLY) + { + if (aiData->abilities[battlerAtk] != ABILITY_TELEPATHY) + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + } + break; + case MOVE_CRAFTY_SHIELD: + if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove) && !(AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + break; + + case MOVE_MAT_BLOCK: + if (gDisableStructs[battlerAtk].isFirstTurn && predictedMove != MOVE_NONE + && !IS_MOVE_STATUS(predictedMove) && !(AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + break; + case MOVE_KINGS_SHIELD: + if (aiData->abilities[battlerAtk] == ABILITY_STANCE_CHANGE //Special logic for Aegislash + && gBattleMons[battlerAtk].species == SPECIES_AEGISLASH_BLADE + && !IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef])) + { + ADJUST_SCORE(GOOD_EFFECT); + break; + } + //fallthrough + default: // protect + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + break; + } + break; + case EFFECT_ENDURE: + if (CanTargetFaintAi(battlerDef, battlerAtk)) + { + if (gBattleMons[battlerAtk].hp > gBattleMons[battlerAtk].maxHP / 4 // Pinch berry couldn't have activated yet + && IsPinchBerryItemEffect(aiData->holdEffects[battlerAtk])) + ADJUST_SCORE(GOOD_EFFECT); + else if ((gBattleMons[battlerAtk].hp > 1) // Only spam endure for Flail/Reversal if you're not at Min Health + && (HasMoveEffect(battlerAtk, EFFECT_FLAIL) || HasMoveEffect(battlerAtk, EFFECT_ENDEAVOR))) + ADJUST_SCORE(GOOD_EFFECT); + } + break; + case EFFECT_SPIKES: + case EFFECT_STEALTH_ROCK: + case EFFECT_STICKY_WEB: + case EFFECT_TOXIC_SPIKES: + if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, aiData)); + { + if (gDisableStructs[battlerAtk].isFirstTurn) + ADJUST_SCORE(BEST_EFFECT); + else + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_FORESIGHT: + if (aiData->abilities[battlerAtk] == ABILITY_SCRAPPY || aiData->abilities[battlerAtk] == ABILITY_MINDS_EYE) + break; + else if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE + || (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) + && (HasMoveWithType(battlerAtk, TYPE_NORMAL) + || HasMoveWithType(battlerAtk, TYPE_FIGHTING)))) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_MIRACLE_EYE: + if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE + || (IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) && (HasMoveWithType(battlerAtk, TYPE_PSYCHIC)))) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_PERISH_SONG: + if (IsBattlerTrapped(battlerDef, TRUE)) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_SANDSTORM: + if (ShouldSetSandstorm(battlerAtk, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerAtk])) + { + ADJUST_SCORE(DECENT_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_SMOOTH_ROCK) + ADJUST_SCORE(WEAK_EFFECT); + if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) + || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) + || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) + ADJUST_SCORE(WEAK_EFFECT); + } + break; + case EFFECT_HAIL: + if (ShouldSetHail(battlerAtk, aiData->abilities[battlerAtk], aiData->holdEffects[battlerAtk])) + { + if ((HasMoveEffect(battlerAtk, EFFECT_AURORA_VEIL) || HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_AURORA_VEIL)) + && ShouldSetScreen(battlerAtk, battlerDef, EFFECT_AURORA_VEIL)) + ADJUST_SCORE(GOOD_EFFECT); + + ADJUST_SCORE(DECENT_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_ICY_ROCK) + ADJUST_SCORE(WEAK_EFFECT); + if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) + || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) + || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) + ADJUST_SCORE(WEAK_EFFECT); + } + break; + case EFFECT_SNOWSCAPE: + if (ShouldSetSnow(battlerAtk, aiData->abilities[battlerAtk], aiData->holdEffects[battlerAtk])) + { + if ((HasMoveEffect(battlerAtk, EFFECT_AURORA_VEIL) || HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_AURORA_VEIL)) + && ShouldSetScreen(battlerAtk, battlerDef, EFFECT_AURORA_VEIL)) + ADJUST_SCORE(GOOD_EFFECT); + + ADJUST_SCORE(DECENT_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_ICY_ROCK) + ADJUST_SCORE(WEAK_EFFECT); + if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) + || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) + || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) + ADJUST_SCORE(WEAK_EFFECT); + } + break; + case EFFECT_RAIN_DANCE: + if (ShouldSetRain(battlerAtk, aiData->abilities[battlerAtk], aiData->holdEffects[battlerAtk])) + { + ADJUST_SCORE(DECENT_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_DAMP_ROCK) + ADJUST_SCORE(WEAK_EFFECT); + if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) + || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) + || HasMoveEffect(battlerDef, EFFECT_SOLAR_BEAM) + || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) + ADJUST_SCORE(WEAK_EFFECT); + if (HasMoveWithType(battlerDef, TYPE_FIRE) || HasMoveWithType(BATTLE_PARTNER(battlerDef), TYPE_FIRE)) + ADJUST_SCORE(WEAK_EFFECT); + } + break; + case EFFECT_SUNNY_DAY: + if (ShouldSetSun(battlerAtk, aiData->abilities[battlerAtk], aiData->holdEffects[battlerAtk])) + { + ADJUST_SCORE(DECENT_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_HEAT_ROCK) + ADJUST_SCORE(WEAK_EFFECT); + if (HasMoveWithType(battlerDef, TYPE_WATER) || HasMoveWithType(BATTLE_PARTNER(battlerDef), TYPE_WATER)) + ADJUST_SCORE(WEAK_EFFECT); + if (HasMoveEffect(battlerDef, EFFECT_THUNDER) || HasMoveEffect(BATTLE_PARTNER(battlerDef), EFFECT_THUNDER)) + ADJUST_SCORE(WEAK_EFFECT); + } + break; + case EFFECT_FELL_STINGER: + if (gBattleMons[battlerAtk].statStages[STAT_ATK] < MAX_STAT_STAGE + && aiData->abilities[battlerAtk] != ABILITY_CONTRARY + && CanIndexMoveFaintTarget(battlerAtk, battlerDef, movesetIndex, 0)) + ADJUST_SCORE(BEST_EFFECT); + break; + case EFFECT_BELLY_DRUM: + if (!CanTargetFaintAi(battlerDef, battlerAtk) + && gBattleMons[battlerAtk].statStages[STAT_ATK] < MAX_STAT_STAGE - 2 + && HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) + && aiData->abilities[battlerAtk] != ABILITY_CONTRARY) + ADJUST_SCORE(BEST_EFFECT); + break; + case EFFECT_PSYCH_UP: + score += AI_ShouldCopyStatChanges(battlerAtk, battlerDef); + break; + case EFFECT_SEMI_INVULNERABLE: + if (predictedMove != MOVE_NONE && !isDoubleBattle) + { + if ((AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) + && (gMovesInfo[predictedMove].effect == EFFECT_EXPLOSION || gMovesInfo[predictedMove].effect == EFFECT_PROTECT)) + ADJUST_SCORE(GOOD_EFFECT); + else if (gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE)) + ADJUST_SCORE(GOOD_EFFECT); + } + break; + case EFFECT_DEFENSE_CURL: + if (HasMoveEffect(battlerAtk, EFFECT_ROLLOUT) && !(gBattleMons[battlerAtk].status2 & STATUS2_DEFENSE_CURL)) + ADJUST_SCORE(DECENT_EFFECT); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score); + break; + case EFFECT_FIRST_TURN_ONLY: + if (ShouldFakeOut(battlerAtk, battlerDef, move) && MoveHasAdditionalEffectWithChance(move, MOVE_EFFECT_FLINCH, 100)) + ADJUST_SCORE(GOOD_EFFECT); + else if (gDisableStructs[battlerAtk].isFirstTurn && GetBestDmgMoveFromBattler(battlerAtk, battlerDef) == move) + ADJUST_SCORE(BEST_EFFECT); + break; + case EFFECT_STOCKPILE: + if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) + break; + if (HasMoveEffect(battlerAtk, EFFECT_SWALLOW) || HasMoveEffect(battlerAtk, EFFECT_SPIT_UP)) + ADJUST_SCORE(DECENT_EFFECT); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score); + break; + case EFFECT_SWAGGER: + case EFFECT_FLATTER: + if (HasMoveEffect(battlerAtk, EFFECT_FOUL_PLAY) + || HasMoveEffect(battlerAtk, EFFECT_PSYCH_UP) + || HasMoveWithAdditionalEffect(battlerAtk, MOVE_EFFECT_SPECTRAL_THIEF)) + ADJUST_SCORE(DECENT_EFFECT); + if (aiData->abilities[battlerDef] == ABILITY_CONTRARY) + ADJUST_SCORE(GOOD_EFFECT); + IncreaseConfusionScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_FURY_CUTTER: + if (!isDoubleBattle && aiData->holdEffects[battlerAtk] == HOLD_EFFECT_METRONOME) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_ATTRACT: + if (!isDoubleBattle + && (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) + && BattlerWillFaintFromSecondaryDamage(battlerDef, aiData->abilities[battlerDef])) + break; // Don't use if the attract won't have a change to activate + if (gBattleMons[battlerDef].status1 & STATUS1_ANY + || (gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + || IsBattlerTrapped(battlerDef, TRUE)) + ADJUST_SCORE(GOOD_EFFECT); + else + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_SAFEGUARD: + if (!AI_IsTerrainAffected(battlerAtk, STATUS_FIELD_MISTY_TERRAIN) || !IsBattlerGrounded(battlerAtk)) + ADJUST_SCORE(DECENT_EFFECT); // TODO: check if opp has status move? + //if (CountUsablePartyMons(battlerDef) != 0) + //ADJUST_SCORE(8); + break; + case EFFECT_PURSUIT: + // TODO + // if (IsPredictedToSwitch(battlerDef, battlerAtk)) + // ADJUST_SCORE(GOOD_EFFECT); + // else if (IsPredictedToUsePursuitableMove(battlerDef, battlerAtk) && !MoveWouldHitFirst(move, battlerAtk, battlerDef)) //Pursuit against fast U-Turn + // ADJUST_SCORE(GOOD_EFFECT); + // break; + case EFFECT_DEFOG: + if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) + || (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST))) + { + ADJUST_SCORE(GOOD_EFFECT); + } + else if (!(gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SPIKES)) //Don't blow away hazards if you set them up + { + if (isDoubleBattle) + { + if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // Partner is going to set up hazards + && AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(battlerAtk), move) == AI_IS_SLOWER) // Partner going first + break; // Don't use Defog if partner is going to set up hazards + } + if (ShouldLowerEvasion(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_TORMENT: + break; + case EFFECT_WILL_O_WISP: + IncreaseBurnScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_FOLLOW_ME: + if (isDoubleBattle + && move != MOVE_SPOTLIGHT + && !IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) + && (move != MOVE_RAGE_POWDER || IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef])) // Rage Powder doesn't affect powder immunities + && IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) + { + u32 predictedMoveOnPartner = gLastMoves[BATTLE_PARTNER(battlerAtk)]; + if (predictedMoveOnPartner != MOVE_NONE && !IS_MOVE_STATUS(predictedMoveOnPartner)) + ADJUST_SCORE(GOOD_EFFECT); + } + break; + case EFFECT_CHARGE: + if (HasDamagingMoveOfType(battlerAtk, TYPE_ELECTRIC)) + ADJUST_SCORE(DECENT_EFFECT); + if (B_CHARGE_SPDEF_RAISE >= GEN_5) + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score); + break; + case EFFECT_TAUNT: + if (IS_MOVE_STATUS(predictedMove)) + ADJUST_SCORE(GOOD_EFFECT); + else if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_STATUS)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_TRICK: + case EFFECT_BESTOW: + switch (aiData->holdEffects[battlerAtk]) + { + case HOLD_EFFECT_CHOICE_SCARF: + ADJUST_SCORE(DECENT_EFFECT); // assume its beneficial + break; + case HOLD_EFFECT_CHOICE_BAND: + if (!HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_CHOICE_SPECS: + if (!HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_TOXIC_ORB: + if (!ShouldPoisonSelf(battlerAtk, aiData->abilities[battlerAtk])) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_FLAME_ORB: + if (!ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk]) && AI_CanBeBurned(battlerAtk, aiData->abilities[battlerDef])) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_BLACK_SLUDGE: + if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON) && aiData->abilities[battlerDef] != ABILITY_MAGIC_GUARD) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_IRON_BALL: + if (!HasMoveEffect(battlerDef, EFFECT_FLING) || !IsBattlerGrounded(battlerDef)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_LAGGING_TAIL: + case HOLD_EFFECT_STICKY_BARB: + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_UTILITY_UMBRELLA: + if (aiData->abilities[battlerAtk] != ABILITY_SOLAR_POWER && aiData->abilities[battlerAtk] != ABILITY_DRY_SKIN) + { + switch (aiData->abilities[battlerDef]) + { + case ABILITY_SWIFT_SWIM: + if (AI_GetWeather(aiData) & B_WEATHER_RAIN) + ADJUST_SCORE(DECENT_EFFECT); // Slow 'em down + break; + case ABILITY_CHLOROPHYLL: + case ABILITY_FLOWER_GIFT: + if (AI_GetWeather(aiData) & B_WEATHER_SUN) + ADJUST_SCORE(DECENT_EFFECT); // Slow 'em down + break; + } + } + break; + case HOLD_EFFECT_EJECT_BUTTON: + //if (!IsRaidBattle() && IsDynamaxed(battlerDef) && gNewBS->dynamaxData.timer[battlerDef] > 1 && + if (HasDamagingMove(battlerAtk) + || (isDoubleBattle && IsBattlerAlive(BATTLE_PARTNER(battlerAtk)) && HasDamagingMove(BATTLE_PARTNER(battlerAtk)))) + ADJUST_SCORE(DECENT_EFFECT); // Force 'em out next turn + break; + default: + if (move != MOVE_BESTOW && aiData->items[battlerAtk] == ITEM_NONE) + { + switch (aiData->holdEffects[battlerDef]) + { + case HOLD_EFFECT_CHOICE_BAND: + break; + case HOLD_EFFECT_TOXIC_ORB: + if (ShouldPoisonSelf(battlerAtk, aiData->abilities[battlerAtk])) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_FLAME_ORB: + if (ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk])) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_BLACK_SLUDGE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON) || aiData->abilities[battlerAtk] == ABILITY_MAGIC_GUARD) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_IRON_BALL: + if (HasMoveEffect(battlerAtk, EFFECT_FLING)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_LAGGING_TAIL: + case HOLD_EFFECT_STICKY_BARB: + break; + default: + ADJUST_SCORE(WEAK_EFFECT); //other hold effects generally universally good + break; + } + } + } + break; + case EFFECT_ROLE_PLAY: + if (!gAbilitiesInfo[aiData->abilities[battlerAtk]].cantBeSuppressed + && !gAbilitiesInfo[aiData->abilities[battlerDef]].cantBeCopied + && !IsAbilityOfRating(aiData->abilities[battlerAtk], 5) + && IsAbilityOfRating(aiData->abilities[battlerDef], 5)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_INGRAIN: + ADJUST_SCORE(WEAK_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_BIG_ROOT) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_MAGIC_COAT: + if (IS_MOVE_STATUS(predictedMove) && AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH)) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_RECYCLE: + if (GetUsedHeldItem(battlerAtk) != ITEM_NONE) + ADJUST_SCORE(WEAK_EFFECT); + if (IsRecycleEncouragedItem(GetUsedHeldItem(battlerAtk))) + ADJUST_SCORE(WEAK_EFFECT); + if (aiData->abilities[battlerAtk] == ABILITY_RIPEN) + { + u32 item = GetUsedHeldItem(battlerAtk); + u32 toHeal = (ItemId_GetHoldEffectParam(item) == 10) ? 10 : gBattleMons[battlerAtk].maxHP / ItemId_GetHoldEffectParam(item); + + if (IsStatBoostingBerry(item) && aiData->hpPercents[battlerAtk] > 60) + ADJUST_SCORE(WEAK_EFFECT); + else if (ShouldRestoreHpBerry(battlerAtk, item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0) + && ((GetWhichBattlerFaster(battlerAtk, battlerDef, TRUE) == 1 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0)) + || !CanTargetFaintAiWithMod(battlerDef, battlerAtk, toHeal, 0))) + ADJUST_SCORE(WEAK_EFFECT); // Recycle healing berry if we can't otherwise faint the target and the target wont kill us after we activate the berry + } + break; + case EFFECT_BRICK_BREAK: + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_REFLECT) + ADJUST_SCORE(DECENT_EFFECT); + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_LIGHTSCREEN) + ADJUST_SCORE(DECENT_EFFECT); + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_AURORA_VEIL) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_SKILL_SWAP: + if (gAbilitiesInfo[aiData->abilities[battlerDef]].aiRating > gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_WORRY_SEED: + case EFFECT_GASTRO_ACID: + case EFFECT_SIMPLE_BEAM: + if (IsAbilityOfRating(aiData->abilities[battlerDef], 5)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_ENTRAINMENT: + if ((IsAbilityOfRating(aiData->abilities[battlerDef], 5) || gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating <= 0) + && (aiData->abilities[battlerDef] != aiData->abilities[battlerAtk] && !(gStatuses3[battlerDef] & STATUS3_GASTRO_ACID))) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_IMPRISON: + if (predictedMove != MOVE_NONE && HasMove(battlerAtk, predictedMove)) + ADJUST_SCORE(DECENT_EFFECT); + else if (gDisableStructs[battlerAtk].isFirstTurn == 0) + ADJUST_SCORE(WEAK_EFFECT); + break; + case EFFECT_REFRESH: + if (gBattleMons[battlerAtk].status1 & STATUS1_ANY) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_TAKE_HEART: + if (gBattleMons[battlerAtk].status1 & STATUS1_ANY + || BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK) + || BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_PSYCHO_SHIFT: + if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY) + IncreasePoisonScore(battlerAtk, battlerDef, move, &score); + else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN) + IncreaseBurnScore(battlerAtk, battlerDef, move, &score); + else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS) + IncreaseParalyzeScore(battlerAtk, battlerDef, move, &score); + else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) + IncreaseSleepScore(battlerAtk, battlerDef, move, &score); + else if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE) + IncreaseFrostbiteScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_GRUDGE: + break; + case EFFECT_SNATCH: + if (predictedMove != MOVE_NONE && gMovesInfo[predictedMove].snatchAffected) + ADJUST_SCORE(GOOD_EFFECT); // Steal move + break; + case EFFECT_MUD_SPORT: + if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC) && HasMoveWithType(battlerDef, TYPE_ELECTRIC)) + ADJUST_SCORE(WEAK_EFFECT); + break; + case EFFECT_WATER_SPORT: + if (!HasMoveWithType(battlerAtk, TYPE_FIRE) && (HasMoveWithType(battlerDef, TYPE_FIRE))) + ADJUST_SCORE(WEAK_EFFECT); + break; + case EFFECT_TICKLE: + if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 && HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) + && aiData->abilities[battlerDef] != ABILITY_CONTRARY && ShouldLowerDefense(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(DECENT_EFFECT); + else if (ShouldLowerAttack(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_COSMIC_POWER: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score); + break; + case EFFECT_BULK_UP: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score); + break; + case EFFECT_CALM_MIND: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score); + break; + case EFFECT_GEOMANCY: + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB) + ADJUST_SCORE(GOOD_EFFECT); + case EFFECT_QUIVER_DANCE: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score); + break; + case EFFECT_VICTORY_DANCE: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score); + break; + case EFFECT_SHELL_SMASH: + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_RESTORE_STATS) + ADJUST_SCORE(WEAK_EFFECT); + + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score); + break; + case EFFECT_TIDY_UP: + IncreaseTidyUpScore(battlerAtk, battlerDef, move, &score); + case EFFECT_DRAGON_DANCE: + case EFFECT_SHIFT_GEAR: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score); + break; + case EFFECT_GUARD_SWAP: + if (gBattleMons[battlerDef].statStages[STAT_DEF] > gBattleMons[battlerAtk].statStages[STAT_DEF] + && gBattleMons[battlerDef].statStages[STAT_SPDEF] >= gBattleMons[battlerAtk].statStages[STAT_SPDEF]) + ADJUST_SCORE(DECENT_EFFECT); + else if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > gBattleMons[battlerAtk].statStages[STAT_SPDEF] + && gBattleMons[battlerDef].statStages[STAT_DEF] >= gBattleMons[battlerAtk].statStages[STAT_DEF]) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_POWER_SWAP: + if (gBattleMons[battlerDef].statStages[STAT_ATK] > gBattleMons[battlerAtk].statStages[STAT_ATK] + && gBattleMons[battlerDef].statStages[STAT_SPATK] >= gBattleMons[battlerAtk].statStages[STAT_SPATK]) + ADJUST_SCORE(DECENT_EFFECT); + else if (gBattleMons[battlerDef].statStages[STAT_SPATK] > gBattleMons[battlerAtk].statStages[STAT_SPATK] + && gBattleMons[battlerDef].statStages[STAT_ATK] >= gBattleMons[battlerAtk].statStages[STAT_ATK]) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_POWER_TRICK: + if (!(gStatuses3[battlerAtk] & STATUS3_POWER_TRICK) + && gBattleMons[battlerAtk].defense > gBattleMons[battlerAtk].attack + && HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_HEART_SWAP: + { + bool32 hasHigherStat = FALSE; + //Only use if all target stats are >= attacker stats to prevent infinite loop + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerDef].statStages[i] < gBattleMons[battlerAtk].statStages[i]) + break; + if (gBattleMons[battlerDef].statStages[i] > gBattleMons[battlerAtk].statStages[i]) + hasHigherStat = TRUE; + } + if (hasHigherStat && i == NUM_BATTLE_STATS) + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_SPEED_SWAP: + if (gBattleMons[battlerDef].speed > gBattleMons[battlerAtk].speed) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_GUARD_SPLIT: + { + u32 newDefense = (gBattleMons[battlerAtk].defense + gBattleMons[battlerDef].defense) / 2; + u32 newSpDef = (gBattleMons[battlerAtk].spDefense + gBattleMons[battlerDef].spDefense) / 2; + + if ((newDefense > gBattleMons[battlerAtk].defense && newSpDef >= gBattleMons[battlerAtk].spDefense) + || (newSpDef > gBattleMons[battlerAtk].spDefense && newDefense >= gBattleMons[battlerAtk].defense)) + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_POWER_SPLIT: + { + u32 newAttack = (gBattleMons[battlerAtk].attack + gBattleMons[battlerDef].attack) / 2; + u32 newSpAtk = (gBattleMons[battlerAtk].spAttack + gBattleMons[battlerDef].spAttack) / 2; + + if ((newAttack > gBattleMons[battlerAtk].attack && newSpAtk >= gBattleMons[battlerAtk].spAttack) + || (newSpAtk > gBattleMons[battlerAtk].spAttack && newAttack >= gBattleMons[battlerAtk].attack)) + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_ELECTRIC_TERRAIN: + case EFFECT_MISTY_TERRAIN: + if (gStatuses3[battlerAtk] & STATUS3_YAWN && IsBattlerGrounded(battlerAtk)) + ADJUST_SCORE(BEST_EFFECT); + case EFFECT_GRASSY_TERRAIN: + case EFFECT_PSYCHIC_TERRAIN: + ADJUST_SCORE(GOOD_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_TERRAIN_EXTENDER) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_PLEDGE: + if (isDoubleBattle && HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_PLEDGE)) + ADJUST_SCORE(GOOD_EFFECT); // Partner might use pledge move + break; + case EFFECT_TRICK_ROOM: + if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) + { + if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) + ADJUST_SCORE(GOOD_EFFECT); + else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) >= GetBattlerSideSpeedAverage(battlerDef)) + ADJUST_SCORE(GOOD_EFFECT); + } + break; + case EFFECT_MAGIC_ROOM: + ADJUST_SCORE(WEAK_EFFECT); + if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_NONE && aiData->holdEffects[battlerDef] != HOLD_EFFECT_NONE) + ADJUST_SCORE(WEAK_EFFECT); + if (isDoubleBattle && aiData->holdEffects[BATTLE_PARTNER(battlerAtk)] == HOLD_EFFECT_NONE && aiData->holdEffects[BATTLE_PARTNER(battlerDef)] != HOLD_EFFECT_NONE) + ADJUST_SCORE(WEAK_EFFECT); + break; + case EFFECT_WONDER_ROOM: + if ((HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) && gBattleMons[battlerAtk].defense < gBattleMons[battlerAtk].spDefense) + || (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) && gBattleMons[battlerAtk].spDefense < gBattleMons[battlerAtk].defense)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_GRAVITY: + if (!(gFieldStatuses & STATUS_FIELD_GRAVITY)) + { + if (HasSleepMoveWithLowAccuracy(battlerAtk, battlerDef)) // Has Gravity for a move like Hypnosis + IncreaseSleepScore(battlerAtk, battlerDef, move, &score); + if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef])) + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_ION_DELUGE: + if ((aiData->abilities[battlerAtk] == ABILITY_VOLT_ABSORB + || aiData->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE + || aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD) + && gMovesInfo[predictedMove].type == TYPE_NORMAL) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_FLING: + /* TODO + switch (gFlingTable[aiData->items[battlerAtk]].effect) + { + case MOVE_EFFECT_BURN: + IncreaseBurnScore(battlerAtk, battlerDef, move, &score); + break; + case MOVE_EFFECT_FLINCH: + score += ShouldTryToFlinch(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move); + break; + case MOVE_EFFECT_PARALYSIS: + IncreaseParalyzeScore(battlerAtk, battlerDef, move, &score); + break; + case MOVE_EFFECT_POISON: + case MOVE_EFFECT_TOXIC: + IncreasePoisonScore(battlerAtk, battlerDef, move, &score); + break; + case MOVE_EFFECT_FREEZE: + if (AI_CanFreeze(battlerAtk, battlerDef)) + ADJUST_SCORE(GOOD_EFFECT); + break; + }*/ + break; + case EFFECT_EMBARGO: + if (aiData->holdEffects[battlerDef] != HOLD_EFFECT_NONE) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_POWDER: + if (predictedMove != MOVE_NONE && !IS_MOVE_STATUS(predictedMove) && gMovesInfo[predictedMove].type == TYPE_FIRE) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_TELEKINESIS: + if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef]) + || !IsBattlerGrounded(battlerDef)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_HEAL_BLOCK: + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && predictedMove != MOVE_NONE && IsHealingMove(predictedMove)) + ADJUST_SCORE(DECENT_EFFECT); // Try to cancel healing move + else if (HasHealingEffect(battlerDef) || aiData->holdEffects[battlerDef] == HOLD_EFFECT_LEFTOVERS + || (aiData->holdEffects[battlerDef] == HOLD_EFFECT_BLACK_SLUDGE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON))) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_SOAK: + if (HasMoveWithType(battlerAtk, TYPE_ELECTRIC) || HasMoveWithType(battlerAtk, TYPE_GRASS) || HasMoveEffect(battlerAtk, EFFECT_FREEZE_DRY)) + ADJUST_SCORE(DECENT_EFFECT); // Get some super effective moves + break; + case EFFECT_THIRD_TYPE: + if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD) + ADJUST_SCORE(DECENT_EFFECT); // Give target more weaknesses + break; + case EFFECT_ELECTRIFY: + if (predictedMove != MOVE_NONE + && (aiData->abilities[battlerAtk] == ABILITY_VOLT_ABSORB + || aiData->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE + || aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD)) + { + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_TOPSY_TURVY: + if (CountPositiveStatStages(battlerDef) > CountNegativeStatStages(battlerDef)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_FAIRY_LOCK: + if (ShouldTrap(battlerAtk, battlerDef, move)) + ADJUST_SCORE(BEST_EFFECT); + break; + case EFFECT_QUASH: + if (isDoubleBattle && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerDef, aiData->partnerMove) == AI_IS_SLOWER) + ADJUST_SCORE(DECENT_EFFECT); // Attacker partner wouldn't go before target + break; + case EFFECT_TAILWIND: + if (GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_LUCKY_CHANT: + if (!isDoubleBattle && CountUsablePartyMons(battlerDef) > 0) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_MAGNET_RISE: + if (IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC) + && !(AI_GetTypeEffectiveness(MOVE_EARTHQUAKE, battlerDef, battlerAtk) == AI_EFFECTIVENESS_x0)) // Doesn't resist ground move + { + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first + { + if (gMovesInfo[predictedMove].type == TYPE_GROUND) + ADJUST_SCORE(GOOD_EFFECT); // Cause the enemy's move to fail + break; + } + else // Opponent Goes First + { + if (HasDamagingMoveOfType(battlerDef, TYPE_GROUND)) + ADJUST_SCORE(DECENT_EFFECT); + break; + } + } + break; + case EFFECT_CAMOUFLAGE: + if (predictedMove != MOVE_NONE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER // Attacker goes first + && !IS_MOVE_STATUS(move) && AI_GetTypeEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_TOXIC_THREAD: + IncreasePoisonScore(battlerAtk, battlerDef, move, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score); + break; + case EFFECT_COUNTER: + if ((!IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) && predictedMove != MOVE_NONE) + && (GetNoOfHitsToKOBattler(battlerDef, battlerAtk, predictedMoveSlot) >= 2) + && (GetBattleMoveCategory(predictedMove) == DAMAGE_CATEGORY_PHYSICAL)) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_MIRROR_COAT: + if ((!IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) && predictedMove != MOVE_NONE) + && (GetNoOfHitsToKOBattler(battlerDef, battlerAtk, predictedMoveSlot) >= 2) + && (GetBattleMoveCategory(predictedMove) == DAMAGE_CATEGORY_SPECIAL)) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_SHORE_UP: + if ((AI_GetWeather(aiData) & B_WEATHER_SANDSTORM) && ShouldRecover(battlerAtk, battlerDef, move, 67)) + ADJUST_SCORE(DECENT_EFFECT); + else if (ShouldRecover(battlerAtk, battlerDef, move, 50)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_FOCUS_PUNCH: + if (!isDoubleBattle && effectiveness > AI_EFFECTIVENESS_x0_5) + { + if (IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef])) + ADJUST_SCORE(DECENT_EFFECT); + if (gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case EFFECT_ENDEAVOR: + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER && !CanTargetFaintAi(battlerDef, battlerAtk)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_REVIVAL_BLESSING: + if (GetFirstFaintedPartyIndex(battlerAtk) != PARTY_SIZE) + ADJUST_SCORE(DECENT_EFFECT); + break; + //case EFFECT_EXTREME_EVOBOOST: // TODO + //break; + //case EFFECT_CLANGOROUS_SOUL: // TODO + //break; + //case EFFECT_NO_RETREAT: // TODO + //break; + //case EFFECT_SKY_DROP + //break; + case EFFECT_JUNGLE_HEALING: + if (ShouldRecover(battlerAtk, battlerDef, move, 25) + || ShouldRecover(BATTLE_PARTNER(battlerAtk), battlerDef, move, 25) + || gBattleMons[battlerAtk].status1 & STATUS1_ANY + || gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 & STATUS1_ANY) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_SALT_CURE: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_WATER) || IS_BATTLER_OF_TYPE(battlerDef, TYPE_STEEL)) + ADJUST_SCORE(DECENT_EFFECT); + break; + } // move effect checks + + // check move additional effects that are likely to happen + for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + { + // Only consider effects with a guaranteed chance to happen + if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], &gMovesInfo[move].additionalEffects[i])) + continue; + + // Consider move effects that target self + if (gMovesInfo[move].additionalEffects[i].self) + { + u32 oneStageStatId = STAT_CHANGE_ATK + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1; + u32 twoStageStatId = STAT_CHANGE_ATK_2 + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1; + + switch (gMovesInfo[move].additionalEffects[i].moveEffect) + { + case MOVE_EFFECT_SPD_PLUS_2: + case MOVE_EFFECT_SPD_PLUS_1: + if (aiData->abilities[battlerAtk] != ABILITY_CONTRARY && !AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) + ADJUST_SCORE(GOOD_EFFECT); + break; + case MOVE_EFFECT_ATK_PLUS_1: + case MOVE_EFFECT_DEF_PLUS_1: + case MOVE_EFFECT_SP_ATK_PLUS_1: + case MOVE_EFFECT_SP_DEF_PLUS_1: + case MOVE_EFFECT_ACC_PLUS_1: + case MOVE_EFFECT_EVS_PLUS_1: + IncreaseStatUpScore(battlerAtk, battlerDef, oneStageStatId, &score); + break; + case MOVE_EFFECT_ATK_PLUS_2: + case MOVE_EFFECT_DEF_PLUS_2: + case MOVE_EFFECT_SP_ATK_PLUS_2: + case MOVE_EFFECT_SP_DEF_PLUS_2: + case MOVE_EFFECT_ACC_PLUS_2: + case MOVE_EFFECT_EVS_PLUS_2: + IncreaseStatUpScore(battlerAtk, battlerDef, twoStageStatId, &score); + break; + // Effects that lower stat(s) - only need to consider Contrary + case MOVE_EFFECT_ATK_MINUS_1: + case MOVE_EFFECT_DEF_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SP_ATK_MINUS_1: + case MOVE_EFFECT_SP_DEF_MINUS_1: + case MOVE_EFFECT_DEF_SPDEF_DOWN: + case MOVE_EFFECT_ATK_DEF_DOWN: + case MOVE_EFFECT_SP_ATK_TWO_DOWN: + if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) + IncreaseStatUpScore(battlerAtk, battlerDef, oneStageStatId, &score); + case MOVE_EFFECT_V_CREATE: + if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) + { + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score); + } + break; + case MOVE_EFFECT_RAPID_SPIN: + if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) + || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED)) + ADJUST_SCORE(GOOD_EFFECT); + break; + } + } + else // consider move effects that hinder the target + { + switch (gMovesInfo[move].additionalEffects[i].moveEffect) + { + case MOVE_EFFECT_FLINCH: + score += ShouldTryToFlinch(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move); + break; + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_2: + if (!ShouldLowerSpeed(battlerAtk, battlerDef, aiData->abilities[battlerDef])) + break; + case MOVE_EFFECT_ATK_MINUS_1: + case MOVE_EFFECT_DEF_MINUS_1: + case MOVE_EFFECT_SP_ATK_MINUS_1: + case MOVE_EFFECT_SP_DEF_MINUS_1: + case MOVE_EFFECT_ACC_MINUS_1: + case MOVE_EFFECT_EVS_MINUS_1: + if (aiData->abilities[battlerDef] != ABILITY_CONTRARY) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_ATK_MINUS_2: + case MOVE_EFFECT_DEF_MINUS_2: + case MOVE_EFFECT_SP_ATK_MINUS_2: + case MOVE_EFFECT_SP_DEF_MINUS_2: + case MOVE_EFFECT_ACC_MINUS_2: + case MOVE_EFFECT_EVS_MINUS_2: + if (aiData->abilities[battlerDef] != ABILITY_CONTRARY) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_POISON: + IncreasePoisonScore(battlerAtk, battlerDef, move, &score); + break; + case MOVE_EFFECT_CLEAR_SMOG: + score += AI_TryToClearStats(battlerAtk, battlerDef, FALSE); + break; + case MOVE_EFFECT_SPECTRAL_THIEF: + score += AI_ShouldCopyStatChanges(battlerAtk, battlerDef); + break; + case MOVE_EFFECT_BUG_BITE: // And pluck + if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD) + break; + else if (ItemId_GetPocket(aiData->items[battlerDef]) == POCKET_BERRY_POUCH) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_INCINERATE: + if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD) + break; + else if (ItemId_GetPocket(aiData->items[battlerDef]) == POCKET_BERRY_POUCH || aiData->holdEffects[battlerDef] == HOLD_EFFECT_GEMS) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_SMACK_DOWN: + if (!IsBattlerGrounded(battlerDef) && HasDamagingMoveOfType(battlerAtk, TYPE_GROUND) && !CanTargetFaintAi(battlerDef, battlerAtk)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_KNOCK_OFF: + if (CanKnockOffItem(battlerDef, aiData->items[battlerDef])) + { + switch (aiData->holdEffects[battlerDef]) + { + case HOLD_EFFECT_IRON_BALL: + if (HasMoveEffect(battlerDef, EFFECT_FLING)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_LAGGING_TAIL: + case HOLD_EFFECT_STICKY_BARB: + break; + default: + ADJUST_SCORE(DECENT_EFFECT); + break; + } + } + break; + case MOVE_EFFECT_STEAL_ITEM: + { + bool32 canSteal = FALSE; + + if (B_TRAINERS_KNOCK_OFF_ITEMS == TRUE) + canSteal = TRUE; + if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER || GetBattlerSide(battlerAtk) == B_SIDE_PLAYER) + canSteal = TRUE; + + if (canSteal && aiData->items[battlerAtk] == ITEM_NONE + && aiData->items[battlerDef] != ITEM_NONE + && CanBattlerGetOrLoseItem(battlerDef, aiData->items[battlerDef]) + && CanBattlerGetOrLoseItem(battlerAtk, aiData->items[battlerDef]) + && !HasMoveEffect(battlerAtk, EFFECT_ACROBATICS) + && aiData->abilities[battlerDef] != ABILITY_STICKY_HOLD) + { + switch (aiData->holdEffects[battlerDef]) + { + case HOLD_EFFECT_NONE: + break; + case HOLD_EFFECT_CHOICE_BAND: + case HOLD_EFFECT_CHOICE_SCARF: + case HOLD_EFFECT_CHOICE_SPECS: + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_TOXIC_ORB: + if (ShouldPoisonSelf(battlerAtk, aiData->abilities[battlerAtk])) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_FLAME_ORB: + if (ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk])) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_BLACK_SLUDGE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_IRON_BALL: + if (HasMoveEffect(battlerAtk, EFFECT_FLING)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case HOLD_EFFECT_LAGGING_TAIL: + case HOLD_EFFECT_STICKY_BARB: + break; + default: + ADJUST_SCORE(WEAK_EFFECT); + break; + } + } + break; + } + break; + case MOVE_EFFECT_STEALTH_ROCK: + case MOVE_EFFECT_SPIKES: + if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, aiData)); + { + if (gDisableStructs[battlerAtk].isFirstTurn) + ADJUST_SCORE(BEST_EFFECT); + else + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case MOVE_EFFECT_FEINT: + if (gMovesInfo[predictedMove].effect == EFFECT_PROTECT) + ADJUST_SCORE(GOOD_EFFECT); + break; + case MOVE_EFFECT_THROAT_CHOP: + if (gMovesInfo[GetBestDmgMoveFromBattler(battlerDef, battlerAtk)].soundMove) + { + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) + ADJUST_SCORE(GOOD_EFFECT); + else + ADJUST_SCORE(DECENT_EFFECT); + } + break; + case MOVE_EFFECT_WRAP: + if (!HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) && ShouldTrap(battlerAtk, battlerDef, move)) + ADJUST_SCORE(BEST_EFFECT); + break; + } + } + } + + if (score <= 1) + return NOT_GOOD_ENOUGH; + else if (score <= 3) + return GOOD_MOVE_EFFECTS; + else if (score <= 5) + return PREFERRED_MOVE_EFFECTS; + else + return BEST_MOVE_EFFECTS; +} + +// AI_FLAG_CHECK_VIABILITY - Chooses best possible move to hit player +static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + // Targeting partner, check benefits of doing that instead + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + return score; + + if (gMovesInfo[move].power) + { + if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) == 0) + ADJUST_SCORE(-20); + else + score += AI_CompareDamagingMoves(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex); + } + + // Calculates score based on effects of a move + score += AI_CalcMoveScore(battlerAtk, battlerDef, move); + + return score; +} + +// Effects that are encouraged on the first turn of battle +static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + u8 i; + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef) + || gBattleResults.battleTurnCounter != 0) + return score; + + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING + && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER + && CanTargetFaintAi(battlerDef, battlerAtk) + && GetMovePriority(battlerAtk, move) == 0) + { + RETURN_SCORE_MINUS(20); // No point in setting up if you will faint. Should just switch if possible.. + } + + // check effects to prioritize first turn + switch (gMovesInfo[move].effect) + { + case EFFECT_ATTACK_UP: + case EFFECT_ATTACK_UP_USER_ALLY: + case EFFECT_DEFENSE_UP: + case EFFECT_SPEED_UP: + case EFFECT_SPECIAL_ATTACK_UP: + case EFFECT_SPECIAL_DEFENSE_UP: + case EFFECT_ACCURACY_UP: + case EFFECT_EVASION_UP: + case EFFECT_ATTACK_DOWN: + case EFFECT_DEFENSE_DOWN: + case EFFECT_SPEED_DOWN: + case EFFECT_SPECIAL_ATTACK_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_ACCURACY_DOWN: + case EFFECT_EVASION_DOWN: + case EFFECT_CONVERSION: + case EFFECT_LIGHT_SCREEN: + case EFFECT_FOCUS_ENERGY: + case EFFECT_CONFUSE: + case EFFECT_ATTACK_UP_2: + case EFFECT_DEFENSE_UP_2: + case EFFECT_DEFENSE_UP_3: + case EFFECT_SPEED_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_3: + case EFFECT_SPECIAL_DEFENSE_UP_2: + case EFFECT_ACCURACY_UP_2: + case EFFECT_EVASION_UP_2: + case EFFECT_ATTACK_DOWN_2: + case EFFECT_DEFENSE_DOWN_2: + case EFFECT_SPEED_DOWN_2: + case EFFECT_SPECIAL_ATTACK_DOWN_2: + case EFFECT_SPECIAL_DEFENSE_DOWN_2: + case EFFECT_ACCURACY_DOWN_2: + case EFFECT_EVASION_DOWN_2: + case EFFECT_REFLECT: + case EFFECT_POISON: + case EFFECT_PARALYZE: + case EFFECT_SUBSTITUTE: + case EFFECT_LEECH_SEED: + case EFFECT_MINIMIZE: + case EFFECT_CURSE: + case EFFECT_SWAGGER: + case EFFECT_CAMOUFLAGE: + case EFFECT_YAWN: + case EFFECT_DEFENSE_CURL: + case EFFECT_TORMENT: + case EFFECT_FLATTER: + case EFFECT_WILL_O_WISP: + case EFFECT_INGRAIN: + case EFFECT_IMPRISON: + case EFFECT_TICKLE: + case EFFECT_COSMIC_POWER: + case EFFECT_BULK_UP: + case EFFECT_CALM_MIND: + case EFFECT_ACUPRESSURE: + case EFFECT_AUTOTOMIZE: + case EFFECT_SHIFT_GEAR: + case EFFECT_SHELL_SMASH: + case EFFECT_GROWTH: + case EFFECT_QUIVER_DANCE: + case EFFECT_ATTACK_SPATK_UP: + case EFFECT_ATTACK_ACCURACY_UP: + case EFFECT_PSYCHIC_TERRAIN: + case EFFECT_GRASSY_TERRAIN: + case EFFECT_ELECTRIC_TERRAIN: + case EFFECT_MISTY_TERRAIN: + case EFFECT_STEALTH_ROCK: + case EFFECT_TOXIC_SPIKES: + case EFFECT_TRICK_ROOM: + case EFFECT_WONDER_ROOM: + case EFFECT_MAGIC_ROOM: + case EFFECT_TAILWIND: + case EFFECT_DRAGON_DANCE: + case EFFECT_TIDY_UP: + case EFFECT_STICKY_WEB: + case EFFECT_RAIN_DANCE: + case EFFECT_SUNNY_DAY: + case EFFECT_SANDSTORM: + case EFFECT_HAIL: + case EFFECT_SNOWSCAPE: + case EFFECT_GEOMANCY: + case EFFECT_VICTORY_DANCE: + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_HIT: + { + // TEMPORARY - should applied to all moves regardless of EFFECT + // Consider move effects + for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + { + switch (gMovesInfo[move].additionalEffects[i].moveEffect) + { + case MOVE_EFFECT_STEALTH_ROCK: + case MOVE_EFFECT_SPIKES: + ADJUST_SCORE(DECENT_EFFECT); + break; + default: + break; + } + } + } + default: + break; + } + + return score; +} + +// Adds score bonus to 'riskier' move effects and high crit moves +static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + u8 i; + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + return score; + + if (gMovesInfo[move].criticalHitStage > 0) + ADJUST_SCORE(DECENT_EFFECT); + + switch (gMovesInfo[move].effect) + { + case EFFECT_SLEEP: + case EFFECT_EXPLOSION: + case EFFECT_MIRROR_MOVE: + case EFFECT_OHKO: + case EFFECT_CONFUSE: + case EFFECT_METRONOME: + case EFFECT_PSYWAVE: + case EFFECT_COUNTER: + case EFFECT_DESTINY_BOND: + case EFFECT_SWAGGER: + case EFFECT_ATTRACT: + case EFFECT_PRESENT: + case EFFECT_BELLY_DRUM: + case EFFECT_MIRROR_COAT: + case EFFECT_FOCUS_PUNCH: + case EFFECT_REVENGE: + case EFFECT_FILLET_AWAY: + if (Random() & 1) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_HIT: + { + // TEMPORARY - should applied to all moves regardless of EFFECT + // Consider move effects + for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + { + switch (gMovesInfo[move].additionalEffects[i].moveEffect) + { + case MOVE_EFFECT_ALL_STATS_UP: + if (Random() & 1) + ADJUST_SCORE(DECENT_EFFECT); + break; + default: + break; + } + } + } + default: + break; + } + + return score; +} + +// Adds score bonus to best powered move +static s32 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + return score; + + if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) == 1) + ADJUST_SCORE(BEST_EFFECT); + else if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) == 2) + ADJUST_SCORE(DECENT_EFFECT); + + return score; +} + +// Prefers moves that are good for baton pass +static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef) + || CountUsablePartyMons(battlerAtk) == 0 + || gMovesInfo[move].power != 0 + || !HasMoveEffect(battlerAtk, EFFECT_BATON_PASS) + || IsBattlerTrapped(battlerAtk, TRUE)) + return score; + + if (IsStatRaisingEffect(gMovesInfo[move].effect)) + { + if (gBattleResults.battleTurnCounter == 0) + ADJUST_SCORE(GOOD_EFFECT); + else if (AI_DATA->hpPercents[battlerAtk] < 60) + ADJUST_SCORE(-10); + else + ADJUST_SCORE(WEAK_EFFECT); + } + + // other specific checks + switch (gMovesInfo[move].effect) + { + case EFFECT_INGRAIN: + if (!(gStatuses3[battlerAtk] & STATUS3_ROOTED)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_AQUA_RING: + if (!(gStatuses3[battlerAtk] & STATUS3_AQUA_RING)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_PROTECT: + if (gLastMoves[battlerAtk] == MOVE_PROTECT || gLastMoves[battlerAtk] == MOVE_DETECT) + ADJUST_SCORE(-2); + else + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_BATON_PASS: + // TODO: Increase Score based on current stats. + if (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING)) + ADJUST_SCORE(DECENT_EFFECT); + if (gStatuses3[battlerAtk] & STATUS3_LEECHSEED) + ADJUST_SCORE(-3); + break; + default: + break; + } + + return score; +} + +static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + u32 effect = gMovesInfo[move].effect; + u32 moveType = gMovesInfo[move].type; + + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + + if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) + { + if ((effect == EFFECT_HEAL_PULSE || effect == EFFECT_HIT_ENEMY_HEAL_ALLY) + || (moveType == TYPE_ELECTRIC && AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_VOLT_ABSORB) + || (moveType == TYPE_GROUND && AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_EARTH_EATER) + || (moveType == TYPE_WATER && (AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_DRY_SKIN || AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_WATER_ABSORB))) + { + if (gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK) + return 0; + + if (CanTargetFaintAi(FOE(battlerAtk), BATTLE_PARTNER(battlerAtk)) + || (CanTargetFaintAi(BATTLE_PARTNER(FOE(battlerAtk)), BATTLE_PARTNER(battlerAtk)))) + ADJUST_SCORE(-1); + + if (AI_DATA->hpPercents[battlerDef] <= 50) + ADJUST_SCORE(WEAK_EFFECT); + } + } + else + { + // Consider AI HP + if (AI_DATA->hpPercents[battlerAtk] > 70) + { + // high hp + switch (effect) + { + case EFFECT_EXPLOSION: + case EFFECT_RESTORE_HP: + case EFFECT_REST: + case EFFECT_DESTINY_BOND: + case EFFECT_FLAIL: + case EFFECT_ENDURE: + case EFFECT_MORNING_SUN: + case EFFECT_SYNTHESIS: + case EFFECT_MOONLIGHT: + case EFFECT_SHORE_UP: + case EFFECT_SOFTBOILED: + case EFFECT_ROOST: + case EFFECT_MEMENTO: + case EFFECT_GRUDGE: + ADJUST_SCORE(-2); + break; + default: + break; + } + } + else if (AI_DATA->hpPercents[battlerAtk] > 30) + { + // med hp + if (IsStatRaisingEffect(effect) || IsStatLoweringEffect(effect)) + ADJUST_SCORE(-2); + + switch (effect) + { + case EFFECT_EXPLOSION: + case EFFECT_BIDE: + case EFFECT_CONVERSION: + case EFFECT_LIGHT_SCREEN: + case EFFECT_MIST: + case EFFECT_FOCUS_ENERGY: + case EFFECT_CONVERSION_2: + case EFFECT_SAFEGUARD: + case EFFECT_BELLY_DRUM: + case EFFECT_FILLET_AWAY: + ADJUST_SCORE(-2); + break; + default: + break; + } + } + else + { + // low hp + if (IsStatRaisingEffect(effect) || IsStatLoweringEffect(effect)) + ADJUST_SCORE(-2); + + // check other discouraged low hp effects + switch (effect) + { + case EFFECT_BIDE: + case EFFECT_CONVERSION: + case EFFECT_REFLECT: + case EFFECT_LIGHT_SCREEN: + case EFFECT_AURORA_VEIL: + case EFFECT_MIST: + case EFFECT_FOCUS_ENERGY: + case EFFECT_RAGE: + case EFFECT_CONVERSION_2: + case EFFECT_LOCK_ON: + case EFFECT_SAFEGUARD: + case EFFECT_BELLY_DRUM: + case EFFECT_PSYCH_UP: + case EFFECT_MIRROR_COAT: + case EFFECT_TICKLE: + case EFFECT_SUNNY_DAY: + case EFFECT_SANDSTORM: + case EFFECT_HAIL: + case EFFECT_SNOWSCAPE: + case EFFECT_RAIN_DANCE: + case EFFECT_FILLET_AWAY: + ADJUST_SCORE(-2); + break; + default: + break; + } + } + } + + // consider target HP + if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + { + ADJUST_SCORE(DECENT_EFFECT); + } + else + { + if (AI_DATA->hpPercents[battlerDef] > 70) + { + // high HP + ; // nothing yet + } + else if (AI_DATA->hpPercents[battlerDef] > 30) + { + // med HP - check discouraged effects + switch (effect) + { + case EFFECT_ATTACK_UP: + case EFFECT_ATTACK_UP_USER_ALLY: + case EFFECT_DEFENSE_UP: + case EFFECT_SPEED_UP: + case EFFECT_SPECIAL_ATTACK_UP: + case EFFECT_SPECIAL_DEFENSE_UP: + case EFFECT_ACCURACY_UP: + case EFFECT_EVASION_UP: + case EFFECT_ATTACK_DOWN: + case EFFECT_DEFENSE_DOWN: + case EFFECT_SPEED_DOWN: + case EFFECT_SPECIAL_ATTACK_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_ACCURACY_DOWN: + case EFFECT_EVASION_DOWN: + case EFFECT_MIST: + case EFFECT_FOCUS_ENERGY: + case EFFECT_ATTACK_UP_2: + case EFFECT_DEFENSE_UP_2: + case EFFECT_SPEED_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_2: + case EFFECT_SPECIAL_DEFENSE_UP_2: + case EFFECT_ACCURACY_UP_2: + case EFFECT_EVASION_UP_2: + case EFFECT_ATTACK_DOWN_2: + case EFFECT_DEFENSE_DOWN_2: + case EFFECT_SPEED_DOWN_2: + case EFFECT_SPECIAL_ATTACK_DOWN_2: + case EFFECT_SPECIAL_DEFENSE_DOWN_2: + case EFFECT_ACCURACY_DOWN_2: + case EFFECT_EVASION_DOWN_2: + case EFFECT_POISON: + case EFFECT_PAIN_SPLIT: + case EFFECT_PERISH_SONG: + case EFFECT_SAFEGUARD: + case EFFECT_TICKLE: + case EFFECT_COSMIC_POWER: + case EFFECT_BULK_UP: + case EFFECT_CALM_MIND: + case EFFECT_DRAGON_DANCE: + case EFFECT_DEFENSE_UP_3: + case EFFECT_SPECIAL_ATTACK_UP_3: + ADJUST_SCORE(-2); + break; + default: + break; + } + } + else + { + // low HP + if (IS_MOVE_STATUS(move)) + ADJUST_SCORE(-2); // don't use status moves if target is at low health + } + } + + return score; +} + +static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + u32 moveEffect = gMovesInfo[move].effect; + + if (gMovesInfo[move].category != DAMAGE_CATEGORY_STATUS || gMovesInfo[AI_DATA->partnerMove].effect == moveEffect) + return score; + + switch (moveEffect) + { + case EFFECT_TAILWIND: + if (!gSideTimers[GetBattlerSide(battlerAtk)].tailwindTimer && !(gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_TRICK_ROOM: + if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && !HasMoveEffect(battlerDef, EFFECT_TRICK_ROOM)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_MAGIC_ROOM: + if (!(gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) && !HasMoveEffect(battlerDef, EFFECT_MAGIC_ROOM)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_WONDER_ROOM: + if (!(gFieldStatuses & STATUS_FIELD_WONDER_ROOM) && !HasMoveEffect(battlerDef, EFFECT_WONDER_ROOM)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_GRAVITY: + if (!(gFieldStatuses & STATUS_FIELD_GRAVITY)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_SAFEGUARD: + if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_SAFEGUARD)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_MIST: + if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_LIGHT_SCREEN: + case EFFECT_REFLECT: + case EFFECT_AURORA_VEIL: + if (ShouldSetScreen(battlerAtk, battlerDef, moveEffect)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_SPIKES: + case EFFECT_STEALTH_ROCK: + case EFFECT_STICKY_WEB: + case EFFECT_TOXIC_SPIKES: + if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, AI_DATA)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_GRASSY_TERRAIN: + if (!(gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_ELECTRIC_TERRAIN: + if (!(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_PSYCHIC_TERRAIN: + if (!(gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_MISTY_TERRAIN: + if (!(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_SANDSTORM: + if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_SANDSTORM | B_WEATHER_PRIMAL_ANY))) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_SUNNY_DAY: + if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_SUN | B_WEATHER_PRIMAL_ANY))) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_RAIN_DANCE: + if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_RAIN | B_WEATHER_PRIMAL_ANY))) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_HAIL: + if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_HAIL | B_WEATHER_PRIMAL_ANY))) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + break; + case EFFECT_SNOWSCAPE: + if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_SNOW | B_WEATHER_PRIMAL_ANY))) + ADJUST_SCORE(POWERFUL_STATUS_MOVE); + } + + return score; +} + +static void AI_Flee(void) +{ + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); +} + +static void AI_Watch(void) +{ + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); +} + +// Roaming pokemon logic +static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + if (IsBattlerTrapped(battlerAtk, FALSE)) + return score; + + AI_Flee(); + return score; +} + +// Safari pokemon logic +static s32 AI_Safari(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + u32 safariFleeRate = gBattleStruct->safariEscapeFactor * 5; // Safari flee rate, from 0-20. + + if ((Random() % 100) < safariFleeRate) + AI_Flee(); + else + AI_Watch(); + + return score; +} + +// First battle logic +static s32 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + if (AI_DATA->hpPercents[battlerDef] <= 20) + AI_Flee(); + + return score; +} diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c deleted file mode 100644 index 96506425d..000000000 --- a/src/battle_ai_script_commands.c +++ /dev/null @@ -1,2068 +0,0 @@ -#include "global.h" -#include "battle.h" -#include "battle_anim.h" -#include "util.h" -#include "item.h" -#include "random.h" -#include "battle_ai_script_commands.h" -#include "constants/abilities.h" -#include "constants/battle_ai.h" -#include "constants/battle_move_effects.h" -#include "constants/moves.h" - -#define AI_ACTION_DONE 0x0001 -#define AI_ACTION_FLEE 0x0002 -#define AI_ACTION_WATCH 0x0004 -#define AI_ACTION_DO_NOT_ATTACK 0x0008 -#define AI_ACTION_UNK5 0x0010 -#define AI_ACTION_UNK6 0x0020 -#define AI_ACTION_UNK7 0x0040 -#define AI_ACTION_UNK8 0x0080 - -#define AI_THINKING_STRUCT (gBattleResources->ai) -#define BATTLE_HISTORY (gBattleResources->battleHistory) - -// AI states -enum -{ - AIState_SettingUp, - AIState_Processing, - AIState_FinishedProcessing, - AIState_DoNotProcess -}; - -/* -sAIScriptPtr is a pointer to the next battle AI cmd command to read. -when a command finishes processing, sAIScriptPtr is incremented by -the number of bytes that the current command had reserved for arguments -in order to read the next command correctly. refer to battle_ai_scripts.s for the -AI scripts. -*/ - -static EWRAM_DATA const u8 *sAIScriptPtr = NULL; -extern u8 *gBattleAI_ScriptsTable[]; - - -// Helper for accessing command arguments and advancing gBattlescriptCurrInstr. -// -// For example accuracycheck is defined as: -// -// .macro accuracycheck failInstr:req, move:req -// .byte 0x1 -// .4byte \failInstr -// .2byte \move -// .endm -// -// Which corresponds to: -// -// CMD_ARGS(const u8 *failInstr, u16 move); -// -// The arguments can be accessed as cmd->failInstr and cmd->move. -// gBattlescriptCurrInstr = cmd->nextInstr; advances to the next instruction. -#define CMD_ARGS(...) const struct __attribute__((packed)) { u8 opcode; MEMBERS(__VA_ARGS__) const u8 nextInstr[0]; } *const cmd UNUSED = (const void *)sAIScriptPtr -#define VARIOUS_ARGS(...) CMD_ARGS(u8 battler, u8 id, ##__VA_ARGS__) -#define NATIVE_ARGS(...) CMD_ARGS(void (*func)(void), ##__VA_ARGS__) - -#define MEMBERS(...) VARARG_8(MEMBERS_, __VA_ARGS__) -#define MEMBERS_0() -#define MEMBERS_1(a) a; -#define MEMBERS_2(a, b) a; b; -#define MEMBERS_3(a, b, c) a; b; c; -#define MEMBERS_4(a, b, c, d) a; b; c; d; -#define MEMBERS_5(a, b, c, d, e) a; b; c; d; e; -#define MEMBERS_6(a, b, c, d, e, f) a; b; c; d; e; f; -#define MEMBERS_7(a, b, c, d, e, f, g) a; b; c; d; e; f; g; -#define MEMBERS_8(a, b, c, d, e, f, g, h) a; b; c; d; e; f; g; h; - -static void Cmd_if_random_less_than(void); -static void Cmd_if_random_greater_than(void); -static void Cmd_if_random_equal(void); -static void Cmd_if_random_not_equal(void); -static void Cmd_score(void); -static void Cmd_if_hp_less_than(void); -static void Cmd_if_hp_more_than(void); -static void Cmd_if_hp_equal(void); -static void Cmd_if_hp_not_equal(void); -static void Cmd_if_status(void); -static void Cmd_if_not_status(void); -static void Cmd_if_status2(void); -static void Cmd_if_not_status2(void); -static void Cmd_if_status3(void); -static void Cmd_if_not_status3(void); -static void Cmd_if_side_affecting(void); -static void Cmd_if_not_side_affecting(void); -static void Cmd_if_less_than(void); -static void Cmd_if_more_than(void); -static void Cmd_if_equal(void); -static void Cmd_if_not_equal(void); -static void Cmd_if_less_than_ptr(void); -static void Cmd_if_more_than_ptr(void); -static void Cmd_if_equal_ptr(void); -static void Cmd_if_not_equal_ptr(void); -static void Cmd_if_move(void); -static void Cmd_if_not_move(void); -static void Cmd_if_in_bytes(void); -static void Cmd_if_not_in_bytes(void); -static void Cmd_if_in_hwords(void); -static void Cmd_if_not_in_hwords(void); -static void Cmd_if_user_has_attacking_move(void); -static void Cmd_if_user_has_no_attacking_moves(void); -static void Cmd_get_turn_count(void); -static void Cmd_get_type(void); -static void Cmd_get_considered_move_power(void); -static void Cmd_get_how_powerful_move_is(void); -static void Cmd_get_last_used_battler_move(void); -static void Cmd_if_equal_(void); -static void Cmd_if_not_equal_(void); -static void Cmd_if_would_go_first(void); -static void Cmd_if_would_not_go_first(void); -static void Cmd_nullsub_2A(void); -static void Cmd_nullsub_2B(void); -static void Cmd_count_alive_pokemon(void); -static void Cmd_get_considered_move(void); -static void Cmd_get_considered_move_effect(void); -static void Cmd_get_ability(void); -static void Cmd_get_highest_type_effectiveness(void); -static void Cmd_if_type_effectiveness(void); -static void Cmd_nullsub_32(void); -static void Cmd_nullsub_33(void); -static void Cmd_if_status_in_party(void); -static void Cmd_if_status_not_in_party(void); -static void Cmd_get_weather(void); -static void Cmd_if_effect(void); -static void Cmd_if_not_effect(void); -static void Cmd_if_stat_level_less_than(void); -static void Cmd_if_stat_level_more_than(void); -static void Cmd_if_stat_level_equal(void); -static void Cmd_if_stat_level_not_equal(void); -static void Cmd_if_can_faint(void); -static void Cmd_if_cant_faint(void); -static void Cmd_if_has_move(void); -static void Cmd_if_doesnt_have_move(void); -static void Cmd_if_has_move_with_effect(void); -static void Cmd_if_doesnt_have_move_with_effect(void); -static void Cmd_if_any_move_disabled_or_encored(void); -static void Cmd_if_curr_move_disabled_or_encored(void); -static void Cmd_flee(void); -static void Cmd_if_random_safari_flee(void); -static void Cmd_watch(void); -static void Cmd_get_hold_effect(void); -static void Cmd_get_gender(void); -static void Cmd_is_first_turn_for(void); -static void Cmd_get_stockpile_count(void); -static void Cmd_is_double_battle(void); -static void Cmd_get_used_held_item(void); -static void Cmd_get_move_type_from_result(void); -static void Cmd_get_move_power_from_result(void); -static void Cmd_get_move_effect_from_result(void); -static void Cmd_get_protect_count(void); -static void Cmd_nullsub_52(void); -static void Cmd_nullsub_53(void); -static void Cmd_nullsub_54(void); -static void Cmd_nullsub_55(void); -static void Cmd_nullsub_56(void); -static void Cmd_nullsub_57(void); -static void Cmd_call(void); -static void Cmd_goto(void); -static void Cmd_end(void); -static void Cmd_if_level_compare(void); -static void Cmd_if_target_taunted(void); -static void Cmd_if_target_not_taunted(void); -static void Cmd_if_status4(void); -static void Cmd_if_not_status4(void); - -static void RecordLastUsedMoveByTarget(void); -static void BattleAI_DoAIProcessing(void); -static void AIStackPushVar(const u8 *ptr); -static bool8 AIStackPop(void); - -typedef void (*BattleAICmdFunc)(void); - -static const BattleAICmdFunc sBattleAICmdTable[] = -{ - Cmd_if_random_less_than, // 0x0 - Cmd_if_random_greater_than, // 0x1 - Cmd_if_random_equal, // 0x2 - Cmd_if_random_not_equal, // 0x3 - Cmd_score, // 0x4 - Cmd_if_hp_less_than, // 0x5 - Cmd_if_hp_more_than, // 0x6 - Cmd_if_hp_equal, // 0x7 - Cmd_if_hp_not_equal, // 0x8 - Cmd_if_status, // 0x9 - Cmd_if_not_status, // 0xA - Cmd_if_status2, // 0xB - Cmd_if_not_status2, // 0xC - Cmd_if_status3, // 0xD - Cmd_if_not_status3, // 0xE - Cmd_if_side_affecting, // 0xF - Cmd_if_not_side_affecting, // 0x10 - Cmd_if_less_than, // 0x11 - Cmd_if_more_than, // 0x12 - Cmd_if_equal, // 0x13 - Cmd_if_not_equal, // 0x14 - Cmd_if_less_than_ptr, // 0x15 - Cmd_if_more_than_ptr, // 0x16 - Cmd_if_equal_ptr, // 0x17 - Cmd_if_not_equal_ptr, // 0x18 - Cmd_if_move, // 0x19 - Cmd_if_not_move, // 0x1A - Cmd_if_in_bytes, // 0x1B - Cmd_if_not_in_bytes, // 0x1C - Cmd_if_in_hwords, // 0x1D - Cmd_if_not_in_hwords, // 0x1E - Cmd_if_user_has_attacking_move, // 0x1F - Cmd_if_user_has_no_attacking_moves, // 0x20 - Cmd_get_turn_count, // 0x21 - Cmd_get_type, // 0x22 - Cmd_get_considered_move_power, // 0x23 - Cmd_get_how_powerful_move_is, // 0x24 - Cmd_get_last_used_battler_move, // 0x25 - Cmd_if_equal_, // 0x26 - Cmd_if_not_equal_, // 0x27 - Cmd_if_would_go_first, // 0x28 - Cmd_if_would_not_go_first, // 0x29 - Cmd_nullsub_2A, // 0x2A - Cmd_nullsub_2B, // 0x2B - Cmd_count_alive_pokemon, // 0x2C - Cmd_get_considered_move, // 0x2D - Cmd_get_considered_move_effect, // 0x2E - Cmd_get_ability, // 0x2F - Cmd_get_highest_type_effectiveness, // 0x30 - Cmd_if_type_effectiveness, // 0x31 - Cmd_nullsub_32, // 0x32 - Cmd_nullsub_33, // 0x33 - Cmd_if_status_in_party, // 0x34 - Cmd_if_status_not_in_party, // 0x35 - Cmd_get_weather, // 0x36 - Cmd_if_effect, // 0x37 - Cmd_if_not_effect, // 0x38 - Cmd_if_stat_level_less_than, // 0x39 - Cmd_if_stat_level_more_than, // 0x3A - Cmd_if_stat_level_equal, // 0x3B - Cmd_if_stat_level_not_equal, // 0x3C - Cmd_if_can_faint, // 0x3D - Cmd_if_cant_faint, // 0x3E - Cmd_if_has_move, // 0x3F - Cmd_if_doesnt_have_move, // 0x40 - Cmd_if_has_move_with_effect, // 0x41 - Cmd_if_doesnt_have_move_with_effect, // 0x42 - Cmd_if_any_move_disabled_or_encored, // 0x43 - Cmd_if_curr_move_disabled_or_encored, // 0x44 - Cmd_flee, // 0x45 - Cmd_if_random_safari_flee, // 0x46 - Cmd_watch, // 0x47 - Cmd_get_hold_effect, // 0x48 - Cmd_get_gender, // 0x49 - Cmd_is_first_turn_for, // 0x4A - Cmd_get_stockpile_count, // 0x4B - Cmd_is_double_battle, // 0x4C - Cmd_get_used_held_item, // 0x4D - Cmd_get_move_type_from_result, // 0x4E - Cmd_get_move_power_from_result, // 0x4F - Cmd_get_move_effect_from_result, // 0x50 - Cmd_get_protect_count, // 0x51 - Cmd_nullsub_52, // 0x52 - Cmd_nullsub_53, // 0x53 - Cmd_nullsub_54, // 0x54 - Cmd_nullsub_55, // 0x55 - Cmd_nullsub_56, // 0x56 - Cmd_nullsub_57, // 0x57 - Cmd_call, // 0x58 - Cmd_goto, // 0x59 - Cmd_end, // 0x5A - Cmd_if_level_compare, // 0x5B - Cmd_if_target_taunted, // 0x5C - Cmd_if_target_not_taunted, // 0x5D - Cmd_if_status4, // 0x5E - Cmd_if_not_status4, // 0x5F -}; - -static const u16 sDiscouragedPowerfulMoveEffects[] = -{ - EFFECT_EXPLOSION, - EFFECT_DREAM_EATER, - EFFECT_TWO_TURNS_ATTACK, - EFFECT_RECHARGE, - EFFECT_SOLAR_BEAM, - EFFECT_SPIT_UP, - EFFECT_FOCUS_PUNCH, - EFFECT_SUPERPOWER, - EFFECT_ERUPTION, - EFFECT_OVERHEAT, - 0xFFFF -}; - -void BattleAI_HandleItemUseBeforeAISetup(void) -{ - s32 i; - u8 *data = (u8 *)BATTLE_HISTORY; - - for (i = 0; i < sizeof(struct BattleHistory); i++) - data[i] = 0; - - // Items are allowed to use in ONLY trainer battles. - if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER) - && (gTrainerBattleOpponent_A != TRAINER_SECRET_BASE) - && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_SAFARI | BATTLE_TYPE_LINK)) - ) - { - for (i = 0; i < MAX_TRAINER_ITEMS; i++) - { - if (gTrainers[gTrainerBattleOpponent_A].items[i] != 0) - { - BATTLE_HISTORY->trainerItems[BATTLE_HISTORY->itemsNo] = gTrainers[gTrainerBattleOpponent_A].items[i]; - BATTLE_HISTORY->itemsNo++; - } - } - } - - // TODO: check if always calling with 0 or 2 is fine - // always called with 0 if first battle of this load or if for any further battle - BattleAI_SetupAIData(0); -} - -void BattleAI_SetupAIData(u32 battler) -{ - s32 i; - u8 *data = (u8 *)AI_THINKING_STRUCT; - u8 moveLimitations; - - // Clear AI data. - for (i = 0; i < sizeof(struct AI_ThinkingStruct); i++) - data[i] = 0; - - for (i = 0; i < MAX_MON_MOVES; i++) - AI_THINKING_STRUCT->score[i] = 100; - - moveLimitations = CheckMoveLimitations(battler, 0, 0xFF); - - // Ignore moves that aren't possible to use. - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBitTable[i] & moveLimitations) - AI_THINKING_STRUCT->score[i] = 0; - - AI_THINKING_STRUCT->simulatedRNG[i] = 100 - (Random() % 16); - } - - gBattleResources->AI_ScriptsStack->size = 0; - gBattlerAttacker = battler; - - // Decide a random target battlerId in doubles. - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - gBattlerTarget = (Random() & BIT_FLANK); - - if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) - gBattlerTarget ^= BIT_FLANK; - } - // There's only one choice in single battles. - else - { - gBattlerTarget = gBattlerAttacker ^ BIT_SIDE; - } - - // Choose proper trainer ai scripts. - // Fire Red, why all the returns?!? - if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) - { - AI_THINKING_STRUCT->aiFlags = AI_SCRIPT_SAFARI; - return; - } - else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) - { - AI_THINKING_STRUCT->aiFlags = AI_SCRIPT_ROAMING; - return; - } - else if (!(gBattleTypeFlags & (BATTLE_TYPE_TRAINER_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_BATTLE_TOWER)) && (gTrainerBattleOpponent_A != TRAINER_SECRET_BASE)) - { - if (gBattleTypeFlags & BATTLE_TYPE_WILD_SCRIPTED) - { - AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE; - return; - } - else if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY_FRLG) - { - AI_THINKING_STRUCT->aiFlags = (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); - return; - } - } - else - { - AI_THINKING_STRUCT->aiFlags = (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); - return; - } - AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags; -} - -u8 BattleAI_ChooseMoveOrAction(void) -{ - u8 currentMoveArray[MAX_MON_MOVES]; - u8 consideredMoveArray[MAX_MON_MOVES]; - u8 numOfBestMoves; - s32 i; - - RecordLastUsedMoveByTarget(); - while (AI_THINKING_STRUCT->aiFlags != 0) - { - if (AI_THINKING_STRUCT->aiFlags & 1) - { - AI_THINKING_STRUCT->aiState = AIState_SettingUp; - BattleAI_DoAIProcessing(); - } - AI_THINKING_STRUCT->aiFlags >>= 1; - AI_THINKING_STRUCT->aiLogicId++; - AI_THINKING_STRUCT->movesetIndex = 0; - } - - // special flee or watch cases for safari. - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) - return AI_CHOICE_FLEE; - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) - return AI_CHOICE_WATCH; - - numOfBestMoves = 1; - currentMoveArray[0] = AI_THINKING_STRUCT->score[0]; - consideredMoveArray[0] = 0; - - for (i = 1; i < MAX_MON_MOVES; i++) - { - if (currentMoveArray[0] < AI_THINKING_STRUCT->score[i]) - { - numOfBestMoves = 1; - currentMoveArray[0] = AI_THINKING_STRUCT->score[i]; - consideredMoveArray[0] = i; - } - if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i]) - { - currentMoveArray[numOfBestMoves] = AI_THINKING_STRUCT->score[i]; - consideredMoveArray[numOfBestMoves++] = i; - } - } - - return consideredMoveArray[Random() % numOfBestMoves]; // break any ties that exist. -} - -static void BattleAI_DoAIProcessing(void) -{ - while (AI_THINKING_STRUCT->aiState != AIState_FinishedProcessing) - { - switch (AI_THINKING_STRUCT->aiState) - { - case AIState_DoNotProcess: // Needed to match. - break; - case AIState_SettingUp: - sAIScriptPtr = gBattleAI_ScriptsTable[AI_THINKING_STRUCT->aiLogicId]; - - if (gBattleMons[gBattlerAttacker].pp[AI_THINKING_STRUCT->movesetIndex] == 0) - { - AI_THINKING_STRUCT->moveConsidered = 0; // Don't consider moves with no PP - } - else - { - AI_THINKING_STRUCT->moveConsidered = gBattleMons[gBattlerAttacker].moves[AI_THINKING_STRUCT->movesetIndex]; - } - AI_THINKING_STRUCT->aiState++; - break; - case AIState_Processing: - if (AI_THINKING_STRUCT->moveConsidered != 0) - { - sBattleAICmdTable[*sAIScriptPtr](); // Run AI command. - } - else - { - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; - AI_THINKING_STRUCT->aiAction |= AI_ACTION_DONE; - } - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_DONE) - { - AI_THINKING_STRUCT->movesetIndex++; - - if (AI_THINKING_STRUCT->movesetIndex < MAX_MON_MOVES && (AI_THINKING_STRUCT->aiAction & AI_ACTION_DO_NOT_ATTACK) == 0) - AI_THINKING_STRUCT->aiState = AIState_SettingUp; // as long as their are more moves to process, keep setting this to setup state. - else - AI_THINKING_STRUCT->aiState++; // done processing. - AI_THINKING_STRUCT->aiAction &= (AI_ACTION_FLEE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK | - AI_ACTION_UNK5 | AI_ACTION_UNK6 | AI_ACTION_UNK7 | AI_ACTION_UNK8); // disable AI_ACTION_DONE. - } - break; - } - } -} - -static void RecordLastUsedMoveByTarget(void) -{ - s32 i; - - for (i = 0; i < 8; i++) - { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i] == 0) - { - BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i] = gLastMoves[gBattlerTarget]; - return; - } - } -} - -// not used -static void ClearBattlerMoveHistory(u8 battlerId) -{ - s32 i; - - for (i = 0; i < 8; i++) - BATTLE_HISTORY->usedMoves[battlerId / 2][i] = MOVE_NONE; -} - -void RecordAbilityBattle(u32 battlerId, u32 abilityId) -{ - BATTLE_HISTORY->abilities[battlerId] = abilityId; - // TODO: AI - // AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability = abilityId; -} - -void RecordItemEffectBattle(u32 battlerId, u32 itemEffect) -{ - BATTLE_HISTORY->itemEffects[battlerId] = itemEffect; - // TODO: AI - // AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect = itemEffect; -} - -static void Cmd_if_random_less_than(void) -{ - if (Random() % 256 < sAIScriptPtr[1]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_if_random_greater_than(void) -{ - if (Random() % 256 > sAIScriptPtr[1]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_if_random_equal(void) -{ - if (Random() % 256 == sAIScriptPtr[1]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_if_random_not_equal(void) -{ - if (Random() % 256 != sAIScriptPtr[1]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_score(void) -{ - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] += sAIScriptPtr[1]; // add the result to the array of the move consider's score. - - if (AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] < 0) // if the score is negative, flatten it to 0. - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; - - sAIScriptPtr += 2; // AI return. -} - -static void Cmd_if_hp_less_than(void) -{ - u16 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if ((u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP) < sAIScriptPtr[2]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 3); - else - sAIScriptPtr += 7; -} - -static void Cmd_if_hp_more_than(void) -{ - u16 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if ((u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP) > sAIScriptPtr[2]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 3); - else - sAIScriptPtr += 7; -} - -static void Cmd_if_hp_equal(void) -{ - u16 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if ((u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP) == sAIScriptPtr[2]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 3); - else - sAIScriptPtr += 7; -} - -static void Cmd_if_hp_not_equal(void) -{ - u16 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if ((u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP) != sAIScriptPtr[2]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 3); - else - sAIScriptPtr += 7; -} - -static void Cmd_if_status(void) -{ - u16 battlerId; - u32 status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - status = T1_READ_32(sAIScriptPtr + 2); - - if (gBattleMons[battlerId].status1 & status) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void Cmd_if_not_status(void) -{ - u16 battlerId; - u32 status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - status = T1_READ_32(sAIScriptPtr + 2); - - if (!(gBattleMons[battlerId].status1 & status)) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void Cmd_if_status2(void) -{ - u16 battlerId; - u32 status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - status = T1_READ_32(sAIScriptPtr + 2); - - if ((gBattleMons[battlerId].status2 & status)) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void Cmd_if_not_status2(void) -{ - u16 battlerId; - u32 status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - status = T1_READ_32(sAIScriptPtr + 2); - - if (!(gBattleMons[battlerId].status2 & status)) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void Cmd_if_status3(void) -{ - u16 battlerId; - u32 status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - status = T1_READ_32(sAIScriptPtr + 2); - - if (gStatuses3[battlerId] & status) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void Cmd_if_not_status3(void) -{ - u16 battlerId; - u32 status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - status = T1_READ_32(sAIScriptPtr + 2); - - if (!(gStatuses3[battlerId] & status)) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void Cmd_if_side_affecting(void) -{ - u16 battlerId; - u32 side, status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - side = GET_BATTLER_SIDE(battlerId); - status = T1_READ_32(sAIScriptPtr + 2); - - if (gSideStatuses[side] & status) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void Cmd_if_not_side_affecting(void) -{ - u16 battlerId; - u32 side, status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - side = GET_BATTLER_SIDE(battlerId); - status = T1_READ_32(sAIScriptPtr + 2); - - if (!(gSideStatuses[side] & status)) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void Cmd_if_less_than(void) -{ - if (AI_THINKING_STRUCT->funcResult < sAIScriptPtr[1]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_if_more_than(void) -{ - if (AI_THINKING_STRUCT->funcResult > sAIScriptPtr[1]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_if_equal(void) -{ - CMD_ARGS(u16 value, const u8 *ptr); - if (AI_THINKING_STRUCT->funcResult == cmd->value) - { - sAIScriptPtr = cmd->ptr; //T1_READ_PTR(sAIScriptPtr + 2); - } - else - { - sAIScriptPtr = cmd->nextInstr; - } -} - -static void Cmd_if_not_equal(void) -{ - CMD_ARGS(u16 value, const u8 *ptr); - if (AI_THINKING_STRUCT->funcResult != cmd->value) - { - sAIScriptPtr = cmd->ptr; //T1_READ_PTR(sAIScriptPtr + 2); - } - else - { - sAIScriptPtr = cmd->nextInstr; - } -} - -static void Cmd_if_less_than_ptr(void) -{ - const u8 *value = T1_READ_PTR(sAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult < *value) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 5); - else - sAIScriptPtr += 9; -} - -static void Cmd_if_more_than_ptr(void) -{ - const u8 *value = T1_READ_PTR(sAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult > *value) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 5); - else - sAIScriptPtr += 9; -} - -static void Cmd_if_equal_ptr(void) -{ - const u8 *value = T1_READ_PTR(sAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult == *value) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 5); - else - sAIScriptPtr += 9; -} - -static void Cmd_if_not_equal_ptr(void) -{ - const u8 *value = T1_READ_PTR(sAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult != *value) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 5); - else - sAIScriptPtr += 9; -} - -static void Cmd_if_move(void) -{ - u16 move = T1_READ_16(sAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->moveConsidered == move) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 3); - else - sAIScriptPtr += 7; -} - -static void Cmd_if_not_move(void) -{ - u16 move = T1_READ_16(sAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->moveConsidered != move) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 3); - else - sAIScriptPtr += 7; -} - -static void Cmd_if_in_bytes(void) -{ - const u8 *ptr = T1_READ_PTR(sAIScriptPtr + 1); - - while (*ptr != 0xFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 5); - return; - } - ptr++; - } - sAIScriptPtr += 9; -} - -static void Cmd_if_not_in_bytes(void) -{ - CMD_ARGS(const u8 *list, const u8 *ptr); - const u8 *ptr = cmd->list; - - while (*ptr != 0xFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - sAIScriptPtr = cmd->nextInstr; - return; - } - ptr++; - } - sAIScriptPtr = cmd->ptr; -} - -static void Cmd_if_in_hwords(void) -{ - const u16 *ptr = (const u16 *)T1_READ_PTR(sAIScriptPtr + 1); - - while (*ptr != 0xFFFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 5); - return; - } - ptr++; - } - sAIScriptPtr += 9; -} - -static void Cmd_if_not_in_hwords(void) -{ - const u16 *ptr = (const u16 *)T1_READ_PTR(sAIScriptPtr + 1); - - while (*ptr != 0xFFFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - sAIScriptPtr += 9; - return; - } - ptr++; - } - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 5); -} - -static void Cmd_if_user_has_attacking_move(void) -{ - s32 i; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[gBattlerAttacker].moves[i] != 0 - && gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].power != 0) - break; - } - - if (i == MAX_MON_MOVES) - sAIScriptPtr += 5; - else - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 1); -} - -static void Cmd_if_user_has_no_attacking_moves(void) -{ - s32 i; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[gBattlerAttacker].moves[i] != 0 - && gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].power != 0) - break; - } - - if (i != MAX_MON_MOVES) - sAIScriptPtr += 5; - else - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 1); -} - -static void Cmd_get_turn_count(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleResults.battleTurnCounter; - sAIScriptPtr += 1; -} - -static void Cmd_get_type(void) -{ - switch (sAIScriptPtr[1]) - { - case AI_TYPE1_USER: - AI_THINKING_STRUCT->funcResult = gBattleMons[gBattlerAttacker].type1; - break; - case AI_TYPE1_TARGET: - AI_THINKING_STRUCT->funcResult = gBattleMons[gBattlerTarget].type1; - break; - case AI_TYPE2_USER: - AI_THINKING_STRUCT->funcResult = gBattleMons[gBattlerAttacker].type2; - break; - case AI_TYPE2_TARGET: - AI_THINKING_STRUCT->funcResult = gBattleMons[gBattlerTarget].type2; - break; - case AI_TYPE_MOVE: - AI_THINKING_STRUCT->funcResult = gMovesInfo[AI_THINKING_STRUCT->moveConsidered].type; - break; - } - sAIScriptPtr += 2; -} - -static void Cmd_get_considered_move_power(void) -{ - AI_THINKING_STRUCT->funcResult = gMovesInfo[AI_THINKING_STRUCT->moveConsidered].power; - sAIScriptPtr += 1; -} - -static void Cmd_get_how_powerful_move_is(void) -{ - s32 i, checkedMove; - s32 moveDmgs[MAX_MON_MOVES]; - - for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) - { - if (gMovesInfo[AI_THINKING_STRUCT->moveConsidered].effect == sDiscouragedPowerfulMoveEffects[i]) - break; - } - - if (gMovesInfo[AI_THINKING_STRUCT->moveConsidered].power > 1 - && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF) - { - gDynamicBasePower = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gMoveResultFlags = 0; - gCritMultiplier = 1; - - for (checkedMove = 0; checkedMove < MAX_MON_MOVES; checkedMove++) - { - for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) - { - if (gMovesInfo[gBattleMons[gBattlerAttacker].moves[checkedMove]].effect == sDiscouragedPowerfulMoveEffects[i]) - break; - } - - if (gBattleMons[gBattlerAttacker].moves[checkedMove] != MOVE_NONE - && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF - && gMovesInfo[gBattleMons[gBattlerAttacker].moves[checkedMove]].power > 1) - { - gCurrentMove = gBattleMons[gBattlerAttacker].moves[checkedMove]; - AI_CalcDmg(gBattlerAttacker, gBattlerTarget); - TypeCalc(gCurrentMove, gBattlerAttacker, gBattlerTarget); - moveDmgs[checkedMove] = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[checkedMove] / 100; - if (moveDmgs[checkedMove] == 0) - moveDmgs[checkedMove] = 1; - } - else - { - moveDmgs[checkedMove] = 0; - } - } - - for (checkedMove = 0; checkedMove < MAX_MON_MOVES; checkedMove++) - { - if (moveDmgs[checkedMove] > moveDmgs[AI_THINKING_STRUCT->movesetIndex]) - break; - } - - if (checkedMove == MAX_MON_MOVES) - AI_THINKING_STRUCT->funcResult = MOVE_MOST_POWERFUL; // Is the most powerful. - else - AI_THINKING_STRUCT->funcResult = MOVE_NOT_MOST_POWERFUL; // Not the most powerful. - } - else - { - AI_THINKING_STRUCT->funcResult = MOVE_POWER_DISCOURAGED; // Highly discouraged in terms of power. - } - - sAIScriptPtr++; -} - -static void Cmd_get_last_used_battler_move(void) -{ - if (sAIScriptPtr[1] == AI_USER) - AI_THINKING_STRUCT->funcResult = gLastMoves[gBattlerAttacker]; - else - AI_THINKING_STRUCT->funcResult = gLastMoves[gBattlerTarget]; - - sAIScriptPtr += 2; -} - -static void Cmd_if_equal_(void) // Same as if_equal. -{ - if (sAIScriptPtr[1] == AI_THINKING_STRUCT->funcResult) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_if_not_equal_(void) // Same as if_not_equal. -{ - if (sAIScriptPtr[1] != AI_THINKING_STRUCT->funcResult) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_if_would_go_first(void) -{ - if ((GetWhichBattlerFaster(gBattlerAttacker, gBattlerTarget, TRUE) == 1) == sAIScriptPtr[1]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_if_would_not_go_first(void) -{ - if ((GetWhichBattlerFaster(gBattlerAttacker, gBattlerTarget, TRUE) == 1) != sAIScriptPtr[1]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_nullsub_2A(void) -{ -} - -static void Cmd_nullsub_2B(void) -{ -} - -static void Cmd_count_alive_pokemon(void) -{ - u8 battlerId; - u8 battlerOnField1, battlerOnField2; - struct Pokemon *party; - s32 i; - - AI_THINKING_STRUCT->funcResult = 0; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) - party = gPlayerParty; - else - party = gEnemyParty; - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - u32 position; - battlerOnField1 = gBattlerPartyIndexes[battlerId]; - position = GetBattlerPosition(battlerId) ^ BIT_FLANK; - battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(position)]; - } - else // In singles there's only one battlerId by side. - { - battlerOnField1 = gBattlerPartyIndexes[battlerId]; - battlerOnField2 = gBattlerPartyIndexes[battlerId]; - } - - for (i = 0; i < PARTY_SIZE; i++) - { - if (i != battlerOnField1 && i != battlerOnField2 - && GetMonData(&party[i], MON_DATA_HP) != 0 - && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE - && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG) - { - AI_THINKING_STRUCT->funcResult++; - } - } - - sAIScriptPtr += 2; -} - -static void Cmd_get_considered_move(void) -{ - AI_THINKING_STRUCT->funcResult = AI_THINKING_STRUCT->moveConsidered; - sAIScriptPtr += 1; -} - -static void Cmd_get_considered_move_effect(void) -{ - AI_THINKING_STRUCT->funcResult = gMovesInfo[AI_THINKING_STRUCT->moveConsidered].effect; - sAIScriptPtr += 1; -} - -static void Cmd_get_ability(void) -{ - u8 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if (GetBattlerSide(battlerId) == AI_TARGET) - { - u16 side = GET_BATTLER_SIDE(battlerId); - - if (BATTLE_HISTORY->abilities[side] != ABILITY_NONE) - { - AI_THINKING_STRUCT->funcResult = BATTLE_HISTORY->abilities[side]; - sAIScriptPtr += 2; - return; - } - - // abilities that prevent fleeing. - if (gBattleMons[battlerId].ability == ABILITY_SHADOW_TAG - || gBattleMons[battlerId].ability == ABILITY_MAGNET_PULL - || gBattleMons[battlerId].ability == ABILITY_ARENA_TRAP) - { - AI_THINKING_STRUCT->funcResult = gBattleMons[battlerId].ability; - sAIScriptPtr += 2; - return; - } - - if (gSpeciesInfo[gBattleMons[battlerId].species].abilities[0] != ABILITY_NONE) - { - if (gSpeciesInfo[gBattleMons[battlerId].species].abilities[1] != ABILITY_NONE) - { - // AI has no knowledge of opponent, so it guesses which ability. - if (Random() % 2) - AI_THINKING_STRUCT->funcResult = gSpeciesInfo[gBattleMons[battlerId].species].abilities[0]; - else - AI_THINKING_STRUCT->funcResult = gSpeciesInfo[gBattleMons[battlerId].species].abilities[1]; - } - else - { - AI_THINKING_STRUCT->funcResult = gSpeciesInfo[gBattleMons[battlerId].species].abilities[0]; - } - } - else - { - // AI can't actually reach this part since no pokemon has ability 2 and no ability 1. - AI_THINKING_STRUCT->funcResult = gSpeciesInfo[gBattleMons[battlerId].species].abilities[1]; - } - } - else - { - // The AI knows its own ability. - AI_THINKING_STRUCT->funcResult = gBattleMons[battlerId].ability; - } - - sAIScriptPtr += 2; -} - -static void Cmd_get_highest_type_effectiveness(void) -{ - s32 i; - u8 *dynamicMoveType; - - gDynamicBasePower = 0; - dynamicMoveType = &gBattleStruct->dynamicMoveType; - *dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gMoveResultFlags = 0; - gCritMultiplier = 1; - AI_THINKING_STRUCT->funcResult = 0; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - gBattleMoveDamage = 40; - gCurrentMove = gBattleMons[gBattlerAttacker].moves[i]; - - if (gCurrentMove != MOVE_NONE) - { - TypeCalc(gCurrentMove, gBattlerAttacker, gBattlerTarget); - - if (gBattleMoveDamage == 120) // Super effective STAB. - gBattleMoveDamage = AI_EFFECTIVENESS_x2; - if (gBattleMoveDamage == 240) - gBattleMoveDamage = AI_EFFECTIVENESS_x4; - if (gBattleMoveDamage == 30) // Not very effective STAB. - gBattleMoveDamage = AI_EFFECTIVENESS_x0_5; - if (gBattleMoveDamage == 15) - gBattleMoveDamage = AI_EFFECTIVENESS_x0_25; - - if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) - gBattleMoveDamage = AI_EFFECTIVENESS_x0; - - if (AI_THINKING_STRUCT->funcResult < gBattleMoveDamage) - AI_THINKING_STRUCT->funcResult = gBattleMoveDamage; - } - } - - sAIScriptPtr += 1; -} - -static void Cmd_if_type_effectiveness(void) -{ - u8 damageVar; - - gDynamicBasePower = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gMoveResultFlags = 0; - gCritMultiplier = 1; - - gBattleMoveDamage = AI_EFFECTIVENESS_x1; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - - TypeCalc(gCurrentMove, gBattlerAttacker, gBattlerTarget); - - if (gBattleMoveDamage == 120) // Super effective STAB. - gBattleMoveDamage = AI_EFFECTIVENESS_x2; - if (gBattleMoveDamage == 240) - gBattleMoveDamage = AI_EFFECTIVENESS_x4; - if (gBattleMoveDamage == 30) // Not very effective STAB. - gBattleMoveDamage = AI_EFFECTIVENESS_x0_5; - if (gBattleMoveDamage == 15) - gBattleMoveDamage = AI_EFFECTIVENESS_x0_25; - - if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) - gBattleMoveDamage = AI_EFFECTIVENESS_x0; - - // Store gBattleMoveDamage in a u8 variable because sAIScriptPtr[1] is a u8. - damageVar = gBattleMoveDamage; - - if (damageVar == sAIScriptPtr[1]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; -} - -static void Cmd_nullsub_32(void) -{ -} - -static void Cmd_nullsub_33(void) -{ -} - -static void Cmd_if_status_in_party(void) -{ - struct Pokemon *party; - struct Pokemon *partyPtr; - int i; - u32 statusToCompareTo; - // u8 battlerId - - // for whatever reason, game freak put the party pointer into 2 variables instead of 1 - // it's possible at some point the switch encompassed the whole function and used each respective variable creating largely duplicate code. - switch (sAIScriptPtr[1]) - { - case 1: - party = partyPtr = gEnemyParty; - break; - default: - party = partyPtr = gPlayerParty; - break; - } - - /* Emerald's fixed version below - switch (sAIScriptPtr[1]) - { - case AI_USER: - battlerId = gBattlerAttacker; - break; - default: - battlerId = gBattlerTarget; - break; - } - - party = (GetBattlerSide(battlerId) == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; - */ - - statusToCompareTo = T1_READ_32(sAIScriptPtr + 2); - - for (i = 0; i < PARTY_SIZE; i++) - { - u16 species = GetMonData(&party[i], MON_DATA_SPECIES); - u16 hp = GetMonData(&party[i], MON_DATA_HP); - u32 status = GetMonData(&party[i], MON_DATA_STATUS); - - if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) - { - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - return; - } - } - - sAIScriptPtr += 10; -} - -// bugged, doesnt return properly. also unused -static void Cmd_if_status_not_in_party(void) -{ - struct Pokemon *party; - struct Pokemon *partyPtr; - int i; - u32 statusToCompareTo; - //u8 battlerId - - switch (sAIScriptPtr[1]) - { - case 1: - party = partyPtr = gEnemyParty; - break; - default: - party = partyPtr = gPlayerParty; - break; - } - - statusToCompareTo = T1_READ_32(sAIScriptPtr + 2); - - for (i = 0; i < PARTY_SIZE; i++) - { - u16 species = GetMonData(&party[i], MON_DATA_SPECIES); - u16 hp = GetMonData(&party[i], MON_DATA_HP); - u32 status = GetMonData(&party[i], MON_DATA_STATUS); - - // everytime the status is found, the AI's logic jumps further and further past its intended destination. this results in a broken AI macro and is probably why it is unused. - if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) - { - sAIScriptPtr += 10; // doesnt return? - #ifdef UBFIX - return; - #endif - } - } - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); -} - -enum -{ - WEATHER_TYPE_SUNNY, - WEATHER_TYPE_RAIN, - WEATHER_TYPE_SANDSTORM, - WEATHER_TYPE_HAIL, -}; - -extern u16 gBattleWeather; - -static void Cmd_get_weather(void) -{ - if (gBattleWeather & B_WEATHER_RAIN) - AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_RAIN; - if (gBattleWeather & B_WEATHER_SANDSTORM) - AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_SANDSTORM; - if (gBattleWeather & B_WEATHER_SUN) - AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_SUNNY; - if (gBattleWeather & B_WEATHER_HAIL_TEMPORARY) - AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_HAIL; - - sAIScriptPtr += 1; -} - -static void Cmd_if_effect(void) -{ - CMD_ARGS(u16 byte, const u8 *ptr); - if (gMovesInfo[AI_THINKING_STRUCT->moveConsidered].effect == cmd->byte) - { - sAIScriptPtr = cmd->ptr; - } - else - { - sAIScriptPtr = cmd->nextInstr; - } -} - -static void Cmd_if_not_effect(void) -{ - CMD_ARGS(u16 byte, const u8 *ptr); - if (gMovesInfo[AI_THINKING_STRUCT->moveConsidered].effect != cmd->byte) - { - sAIScriptPtr = cmd->ptr; - } - else - { - sAIScriptPtr = cmd->nextInstr; - } -} - -static void Cmd_if_stat_level_less_than(void) -{ - u32 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if (gBattleMons[battlerId].statStages[sAIScriptPtr[2]] < sAIScriptPtr[3]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 4); - else - sAIScriptPtr += 8; -} - -static void Cmd_if_stat_level_more_than(void) -{ - u32 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if (gBattleMons[battlerId].statStages[sAIScriptPtr[2]] > sAIScriptPtr[3]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 4); - else - sAIScriptPtr += 8; -} - -static void Cmd_if_stat_level_equal(void) -{ - u32 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if (gBattleMons[battlerId].statStages[sAIScriptPtr[2]] == sAIScriptPtr[3]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 4); - else - sAIScriptPtr += 8; -} - -static void Cmd_if_stat_level_not_equal(void) -{ - u32 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if (gBattleMons[battlerId].statStages[sAIScriptPtr[2]] != sAIScriptPtr[3]) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 4); - else - sAIScriptPtr += 8; -} - -static void Cmd_if_can_faint(void) -{ - if (gMovesInfo[AI_THINKING_STRUCT->moveConsidered].power < 2) - { - sAIScriptPtr += 5; - return; - } - - gDynamicBasePower = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gMoveResultFlags = 0; - gCritMultiplier = 1; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - AI_CalcDmg(gBattlerAttacker, gBattlerTarget); - TypeCalc(gCurrentMove, gBattlerAttacker, gBattlerTarget); - - gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; - - // Moves always do at least 1 damage. - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - - if (gBattleMons[gBattlerTarget].hp <= gBattleMoveDamage) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 1); - else - sAIScriptPtr += 5; -} - -static void Cmd_if_cant_faint(void) -{ - if (gMovesInfo[AI_THINKING_STRUCT->moveConsidered].power < 2) - { - sAIScriptPtr += 5; - return; - } - - gDynamicBasePower = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gMoveResultFlags = 0; - gCritMultiplier = 1; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - AI_CalcDmg(gBattlerAttacker, gBattlerTarget); - TypeCalc(gCurrentMove, gBattlerAttacker, gBattlerTarget); - - gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; - - // This macro is missing the damage 0 = 1 assumption. - - if (gBattleMons[gBattlerTarget].hp > gBattleMoveDamage) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 1); - else - sAIScriptPtr += 5; -} - -static void Cmd_if_has_move(void) -{ - int i; - const u16 *movePtr = (u16 *)(sAIScriptPtr + 2); - - switch (sAIScriptPtr[1]) - { - case AI_USER: - case AI_USER_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[gBattlerAttacker].moves[i] == *movePtr) - break; - } - if (i == MAX_MON_MOVES) - sAIScriptPtr += 8; - else - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 4); - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < 8; i++) - { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i] == *movePtr) - break; - } - if (i == 8) - sAIScriptPtr += 8; - else - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 4); - break; - } -} - -static void Cmd_if_doesnt_have_move(void) -{ - int i; - const u16 *movePtr = (u16 *)(sAIScriptPtr + 2); - - switch (sAIScriptPtr[1]) - { - case AI_USER: - case AI_USER_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[gBattlerAttacker].moves[i] == *movePtr) - break; - } - if (i != MAX_MON_MOVES) - sAIScriptPtr += 8; - else - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 4); - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < 8; i++) - { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i] == *movePtr) - break; - } - if (i != 8) - sAIScriptPtr += 8; - else - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 4); - break; - } -} - -static void Cmd_if_has_move_with_effect(void) -{ - CMD_ARGS(u8 battler, u16 effect, const u8 *ptr); - int i; - - switch (cmd->battler) - { - case AI_USER: - case AI_USER_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[gBattlerAttacker].moves[i] != 0 && gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].effect == cmd->effect) - break; - } - if (i != MAX_MON_MOVES) - sAIScriptPtr = cmd->ptr; - else - sAIScriptPtr = cmd->nextInstr; - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < 8; i++) - { - if (gBattleMons[gBattlerAttacker].moves[i] != 0 && gMovesInfo[BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i]].effect == cmd->effect) - break; - } - sAIScriptPtr = cmd->ptr; - } -} - -static void Cmd_if_doesnt_have_move_with_effect(void) -{ - CMD_ARGS(u8 battler, u16 effect, const u8 *ptr); - int i; - - switch (cmd->battler) - { - case AI_USER: - case AI_USER_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[gBattlerAttacker].moves[i] != 0 && gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].effect == cmd->effect) - break; - } - if (i != MAX_MON_MOVES) - sAIScriptPtr = cmd->nextInstr; - else - sAIScriptPtr = cmd->ptr; - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < 8; i++) - { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i] != 0 && gMovesInfo[BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i]].effect == cmd->effect) - break; - } - sAIScriptPtr = cmd->nextInstr; - } -} - -static void Cmd_if_any_move_disabled_or_encored(void) -{ - u8 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if (sAIScriptPtr[2] == 0) - { - if (gDisableStructs[battlerId].disabledMove == MOVE_NONE) - sAIScriptPtr += 7; - else - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 3); - } - else if (sAIScriptPtr[2] != 1) - { - sAIScriptPtr += 7; - } - else - { - if (gDisableStructs[battlerId].encoredMove != MOVE_NONE) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 3); - else - sAIScriptPtr += 7; - } -} - -static void Cmd_if_curr_move_disabled_or_encored(void) -{ - u8 battler = sAIScriptPtr[1]; - switch (battler) - { - case AI_TARGET: - if (gDisableStructs[battler].disabledMove == AI_THINKING_STRUCT->moveConsidered) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; - break; - case AI_USER: - if (gDisableStructs[battler].encoredMove == AI_THINKING_STRUCT->moveConsidered) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - else - sAIScriptPtr += 6; - break; - default: - sAIScriptPtr += 6; - break; - } -} - -static void Cmd_flee(void) -{ - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); // what matters is AI_ACTION_FLEE being enabled. -} - -static void Cmd_if_random_safari_flee(void) -{ - u8 safariFleeRate; - - if (gBattleStruct->safariRockThrowCounter) - { - safariFleeRate = gBattleStruct->safariEscapeFactor * 2; - if (safariFleeRate > 20) - safariFleeRate = 20; - } - else if (gBattleStruct->safariBaitThrowCounter != 0) - { - safariFleeRate = gBattleStruct->safariEscapeFactor / 4; - if (safariFleeRate == 0) - safariFleeRate = 1; - } - else - safariFleeRate = gBattleStruct->safariEscapeFactor; - safariFleeRate *= 5; - if ((u8)(Random() % 100) < safariFleeRate) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 1); - else - sAIScriptPtr += 5; -} - -static void Cmd_watch(void) -{ - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); // what matters is AI_ACTION_WATCH being enabled. -} - -static void Cmd_get_hold_effect(void) -{ - u8 battlerId; - u16 side; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) - { - side = GET_BATTLER_SIDE(battlerId); - AI_THINKING_STRUCT->funcResult = BATTLE_HISTORY->itemEffects[side]; - } - else - AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(gBattleMons[battlerId].item); - - sAIScriptPtr += 2; -} - -static void Cmd_get_gender(void) -{ - u8 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerId].species, gBattleMons[battlerId].personality); - - sAIScriptPtr += 2; -} - -static void Cmd_is_first_turn_for(void) -{ - u8 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = gDisableStructs[battlerId].isFirstTurn; - - sAIScriptPtr += 2; -} - -static void Cmd_get_stockpile_count(void) -{ - u8 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = gDisableStructs[battlerId].stockpileCounter; - - sAIScriptPtr += 2; -} - -static void Cmd_is_double_battle(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleTypeFlags & BATTLE_TYPE_DOUBLE; - - sAIScriptPtr += 1; -} - -static void Cmd_get_used_held_item(void) -{ - u8 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = gBattleStruct->usedHeldItems[battlerId][GetBattlerSide(battlerId)]; - sAIScriptPtr += 2; -} - -static void Cmd_get_move_type_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = gMovesInfo[AI_THINKING_STRUCT->funcResult].type; - - sAIScriptPtr += 1; -} - -static void Cmd_get_move_power_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = gMovesInfo[AI_THINKING_STRUCT->funcResult].power; - - sAIScriptPtr += 1; -} - -static void Cmd_get_move_effect_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = gMovesInfo[AI_THINKING_STRUCT->funcResult].effect; - - sAIScriptPtr += 1; -} - -static void Cmd_get_protect_count(void) -{ - u8 battlerId; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = gDisableStructs[battlerId].protectUses; - - sAIScriptPtr += 2; -} - -static void Cmd_nullsub_52(void) -{ -} - -static void Cmd_nullsub_53(void) -{ -} - -static void Cmd_nullsub_54(void) -{ -} - -static void Cmd_nullsub_55(void) -{ -} - -static void Cmd_nullsub_56(void) -{ -} - -static void Cmd_nullsub_57(void) -{ -} - -static void Cmd_call(void) -{ - AIStackPushVar(sAIScriptPtr + 5); - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 1); -} - -static void Cmd_goto(void) -{ - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 1); -} - -static void Cmd_end(void) -{ - if (AIStackPop() == FALSE) - AI_THINKING_STRUCT->aiAction |= AI_ACTION_DONE; -} - -static void Cmd_if_level_compare(void) -{ - switch (sAIScriptPtr[1]) - { - case 0: // greater than - if (gBattleMons[gBattlerAttacker].level > gBattleMons[gBattlerTarget].level) - { - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - return; - } - sAIScriptPtr += 6; - return; - case 1: // less than - if (gBattleMons[gBattlerAttacker].level < gBattleMons[gBattlerTarget].level) - { - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - return; - } - sAIScriptPtr += 6; - return; - case 2: // equal - if (gBattleMons[gBattlerAttacker].level == gBattleMons[gBattlerTarget].level) - { - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2); - return; - } - sAIScriptPtr += 6; - return; - } -} - -static void Cmd_if_target_taunted(void) -{ - if (gDisableStructs[gBattlerTarget].tauntTimer != 0) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 1); - else - sAIScriptPtr += 5; -} - -static void Cmd_if_target_not_taunted(void) -{ - if (gDisableStructs[gBattlerTarget].tauntTimer == 0) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 1); - else - sAIScriptPtr += 5; -} - -static void Cmd_if_status4(void) -{ - u16 battlerId; - u32 status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - status = T1_READ_32(sAIScriptPtr + 2); - - if (gStatuses4[battlerId] & status) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void Cmd_if_not_status4(void) -{ - u16 battlerId; - u32 status; - - if (sAIScriptPtr[1] == AI_USER) - battlerId = gBattlerAttacker; - else - battlerId = gBattlerTarget; - - status = T1_READ_32(sAIScriptPtr + 2); - - if (!(gStatuses4[battlerId] & status)) - sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 6); - else - sAIScriptPtr += 10; -} - -static void AIStackPushVar(const u8 *var) -{ - gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = var; -} - -// unused -static void AIStackPushVar_cursor(void) -{ - gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = sAIScriptPtr; -} - -static bool8 AIStackPop(void) -{ - if (gBattleResources->AI_ScriptsStack->size != 0) - { - --gBattleResources->AI_ScriptsStack->size; - sAIScriptPtr = gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size]; - return TRUE; - } - else - return FALSE; -} diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index b9a4b8b18..0c6206a62 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -1,27 +1,228 @@ #include "global.h" #include "battle.h" +#include "constants/battle_ai.h" +#include "battle_ai_main.h" +#include "battle_ai_util.h" +#include "battle_util.h" #include "battle_anim.h" #include "battle_controllers.h" +#include "battle_main.h" +#include "constants/hold_effects.h" +#include "battle_setup.h" +#include "data.h" #include "item.h" +#include "party_menu.h" +#include "pokemon.h" #include "random.h" #include "util.h" #include "constants/abilities.h" #include "constants/item_effects.h" +#include "constants/battle_move_effects.h" #include "constants/items.h" #include "constants/moves.h" -#include "constants/pokemon.h" -static bool8 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool8 noRng); -static bool8 FindMonWithFlagsAndSuperEffective(u32 battler, u8 flags, u8 moduloPercent); -static bool8 ShouldUseItem(u32 battler); +// this file's functions +static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng); +static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 moduloPercent, bool32 emitResult); +static bool32 ShouldUseItem(u32 battler); +static bool32 AiExpectsToFaintPlayer(u32 battler); +static bool32 AI_ShouldHeal(u32 battler, u32 healAmount); +static bool32 AI_OpponentCanFaintAiWithMod(u32 battler, u32 healAmount); +static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon); -static bool8 ShouldSwitchIfPerishSong(u32 battler) +static void InitializeSwitchinCandidate(struct Pokemon *mon) { - if (gStatuses3[battler] & STATUS3_PERISH_SONG - && gDisableStructs[battler].perishSongTimer == 0) + PokemonToBattleMon(mon, &AI_DATA->switchinCandidate.battleMon); + AI_DATA->switchinCandidate.hypotheticalStatus = FALSE; +} + +static bool32 IsAceMon(u32 battler, u32 monPartyId) +{ + if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON + && !(gBattleStruct->forcedSwitch & gBitTable[battler]) + && monPartyId == CalculateEnemyPartyCount()-1) + return TRUE; + return FALSE; +} + +void GetAIPartyIndexes(u32 battler, s32 *firstId, s32 *lastId) +{ + if (BATTLE_TWO_VS_ONE_OPPONENT && (battler & BIT_SIDE) == B_SIDE_OPPONENT) { - *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = PARTY_SIZE; - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + *firstId = 0, *lastId = PARTY_SIZE; + } + else if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_TOWER_LINK_MULTI)) + { + if ((battler & BIT_FLANK) == B_FLANK_LEFT) + *firstId = 0, *lastId = PARTY_SIZE / 2; + else + *firstId = PARTY_SIZE / 2, *lastId = PARTY_SIZE; + } + else + { + *firstId = 0, *lastId = PARTY_SIZE; + } +} + +// Note that as many return statements as possible are INTENTIONALLY put after all of the loops; +// the function can take a max of about 0.06s to run, and this prevents the player from identifying +// whether the mon will switch or not by seeing how long the delay is before they select a move +static bool32 HasBadOdds(u32 battler, bool32 emitResult) +{ + //Variable initialization + u8 opposingPosition, atkType1, atkType2, defType1, defType2, effectiveness; + s32 i, damageDealt = 0, maxDamageDealt = 0, damageTaken = 0, maxDamageTaken = 0; + u32 aiMove, playerMove, aiBestMove = MOVE_NONE, aiAbility = GetBattlerAbility(battler), opposingBattler, weather = AI_GetWeather(AI_DATA); + bool32 getsOneShot = FALSE, hasStatusMove = FALSE, hasSuperEffectiveMove = FALSE; + u16 typeEffectiveness = UQ_4_12(1.0), aiMoveEffect; //baseline typing damage + + // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer + if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) + return FALSE; + + // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + return FALSE; + + opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); + opposingBattler = GetBattlerAtPosition(opposingPosition); + + // Gets types of player (opposingBattler) and computer (battler) + atkType1 = gBattleMons[opposingBattler].type1; + atkType2 = gBattleMons[opposingBattler].type2; + defType1 = gBattleMons[battler].type1; + defType2 = gBattleMons[battler].type2; + + // Check AI moves for damage dealt + for (i = 0; i < MAX_MON_MOVES; i++) + { + aiMove = gBattleMons[battler].moves[i]; + aiMoveEffect = gMovesInfo[aiMove].effect; + if (aiMove != MOVE_NONE) + { + // Check if mon has an "important" status move + if (aiMoveEffect == EFFECT_REFLECT || aiMoveEffect == EFFECT_LIGHT_SCREEN + || aiMoveEffect == EFFECT_SPIKES || aiMoveEffect == EFFECT_TOXIC_SPIKES || aiMoveEffect == EFFECT_STEALTH_ROCK || aiMoveEffect == EFFECT_STICKY_WEB || aiMoveEffect == EFFECT_LEECH_SEED + || aiMoveEffect == EFFECT_EXPLOSION + || aiMoveEffect == EFFECT_SLEEP || aiMoveEffect == EFFECT_YAWN || aiMoveEffect == EFFECT_TOXIC || aiMoveEffect == EFFECT_WILL_O_WISP || aiMoveEffect == EFFECT_PARALYZE + || aiMoveEffect == EFFECT_TRICK || aiMoveEffect == EFFECT_TRICK_ROOM || aiMoveEffect== EFFECT_WONDER_ROOM || aiMoveEffect == EFFECT_PSYCHO_SHIFT || aiMoveEffect == EFFECT_FIRST_TURN_ONLY + ) + { + hasStatusMove = TRUE; + } + + // Only check damage if move has power + if (gMovesInfo[aiMove].power != 0) + { + // Check if mon has a super effective move + if (AI_GetTypeEffectiveness(aiMove, battler, opposingBattler) >= UQ_4_12(2.0)) + hasSuperEffectiveMove = TRUE; + + // Get maximum damage mon can deal + damageDealt = AI_DATA->simulatedDmg[battler][opposingBattler][i]; + if(damageDealt > maxDamageDealt) + { + maxDamageDealt = damageDealt; + aiBestMove = aiMove; + } + + } + } + } + + // Calculate type advantage + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType1))); + if (atkType2 != atkType1) + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType1))); + if (defType2 != defType1) + { + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType2))); + if (atkType2 != atkType1) + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType2))); + } + + // Get max damage mon could take + for (i = 0; i < MAX_MON_MOVES; i++) + { + playerMove = gBattleMons[opposingBattler].moves[i]; + if (playerMove != MOVE_NONE && gMovesInfo[playerMove].power != 0) + { + damageTaken = AI_CalcDamage(playerMove, opposingBattler, battler, &effectiveness, FALSE, weather); + if (damageTaken > maxDamageTaken) + maxDamageTaken = damageTaken; + } + } + + // Check if mon gets one shot + if(maxDamageTaken > gBattleMons[battler].hp) + { + getsOneShot = TRUE; + } + + // Check if current mon can outspeed and KO in spite of bad matchup, and don't switch out if it can + if(damageDealt > gBattleMons[opposingBattler].hp) + { + if (AI_WhoStrikesFirst(battler, opposingBattler, aiBestMove) == AI_IS_FASTER) + return FALSE; + } + + // If we don't have any other viable options, don't switch out + if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE) + return FALSE; + + // Start assessing whether or not mon has bad odds + // Jump straight to swtiching out in cases where mon gets OHKO'd + if (((getsOneShot && gBattleMons[opposingBattler].speed > gBattleMons[battler].speed) // If the player OHKOs and outspeeds OR OHKOs, doesn't outspeed but isn't 2HKO'd + || (getsOneShot && gBattleMons[opposingBattler].speed <= gBattleMons[battler].speed && maxDamageDealt < gBattleMons[opposingBattler].hp / 2)) + && (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2 // And the current mon has at least 1/2 their HP, or 1/4 HP and Regenerator + || (aiAbility == ABILITY_REGENERATOR + && gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4))) + { + // 50% chance to stay in regardless + if (Random() % 2 == 0) + return FALSE; + + // Switch mon out + gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + return TRUE; + } + + // General bad type matchups have more wiggle room + if (typeEffectiveness >= UQ_4_12(2.0)) // If the player has at least a 2x type advantage + { + if (!hasSuperEffectiveMove // If the AI doesn't have a super effective move + && (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2 // And the current mon has at least 1/2 their HP, or 1/4 HP and Regenerator + || (aiAbility == ABILITY_REGENERATOR + && gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4))) + { + // Then check if they have an important status move, which is worth using even in a bad matchup + if (hasStatusMove) + return FALSE; + + // 50% chance to stay in regardless + if (Random() % 2 == 0) + return FALSE; + + // Switch mon out + gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + return TRUE; + } + } + return FALSE; +} + +static bool32 ShouldSwitchIfAllBadMoves(u32 battler, bool32 emitResult) +{ + if (AI_DATA->shouldSwitchMon & gBitTable[battler]) + { + AI_DATA->shouldSwitchMon &= ~(gBitTable[battler]); + gBattleStruct->AI_monToSwitchIntoId[battler] = AI_DATA->monToSwitchId[battler]; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SWITCH, 0); return TRUE; } else @@ -30,68 +231,92 @@ static bool8 ShouldSwitchIfPerishSong(u32 battler) } } -static bool8 ShouldSwitchIfWonderGuard(u32 battler) +static bool32 ShouldSwitchIfWonderGuard(u32 battler, bool32 emitResult) { + u8 opposingPosition; u8 opposingBattler; - u8 moveFlags; s32 i, j; + s32 firstId; + s32 lastId; // + 1 + struct Pokemon *party = NULL; u16 move; if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) return FALSE; - if (gBattleMons[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)].ability == ABILITY_WONDER_GUARD) + + opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); + + if (GetBattlerAbility(GetBattlerAtPosition(opposingPosition)) != ABILITY_WONDER_GUARD) + return FALSE; + + // Check if Pokémon has a super effective move. + for (opposingBattler = GetBattlerAtPosition(opposingPosition), i = 0; i < MAX_MON_MOVES; i++) { - // Check if Pokemon has a super effective move. - for (opposingBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT), i = 0; i < MAX_MON_MOVES; ++i) + move = gBattleMons[battler].moves[i]; + if (move != MOVE_NONE) { - move = gBattleMons[battler].moves[i]; - if (move == MOVE_NONE) - continue; - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE) + if (AI_GetTypeEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0)) return FALSE; } - // Find a Pokemon in the party that has a super effective move. - for (i = 0; i < PARTY_SIZE; ++i) + } + + // Get party information. + GetAIPartyIndexes(battler, &firstId, &lastId); + + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + // Find a Pokémon in the party that has a super effective move. + for (i = firstId; i < lastId; i++) + { + if (!IsValidForBattle(&party[i])) + continue; + if (i == gBattlerPartyIndexes[battler]) + continue; + if (IsAceMon(battler, i)) + continue; + + for (opposingBattler = GetBattlerAtPosition(opposingPosition), j = 0; j < MAX_MON_MOVES; j++) { - if (GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0 - || GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE - || GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG - || i == gBattlerPartyIndexes[battler]) - continue; - GetMonData(&gEnemyParty[i], MON_DATA_SPECIES); // Unused return value. - GetMonData(&gEnemyParty[i], MON_DATA_ABILITY_NUM); // Unused return value. - for (opposingBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT), j = 0; j < MAX_MON_MOVES; ++j) + move = GetMonData(&party[i], MON_DATA_MOVE1 + j); + if (move != MOVE_NONE) { - move = GetMonData(&gEnemyParty[i], MON_DATA_MOVE1 + j); - if (move == MOVE_NONE) - continue; - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE && Random() % 3 < 2) + if (AI_GetTypeEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0) && Random() % 3 < 2) { // We found a mon. - *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = i; - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + gBattleStruct->AI_monToSwitchIntoId[battler] = i; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SWITCH, 0); return TRUE; } } } } - return FALSE; // There is not a single Pokemon in the party that has a super effective move against a mon with Wonder Guard. + + return FALSE; // There is not a single Pokémon in the party that has a super effective move against a mon with Wonder Guard. } -static bool8 FindMonThatAbsorbsOpponentsMove(u32 battler) +static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler, bool32 emitResult) { u8 battlerIn1, battlerIn2; - u16 absorbingTypeAbility; - s32 i; + u8 numAbsorbingAbilities = 0; + u16 absorbingTypeAbilities[3]; // Array size is maximum number of absorbing abilities for a single type + s32 firstId; + s32 lastId; // + 1 + struct Pokemon *party; + s32 i, j; - if ((HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && Random() % 3) - || (gLastLandedMoves[battler] == MOVE_NONE)) + if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && Random() % 3 != 0) return FALSE; - if (gLastLandedMoves[battler] == 0xFFFF - || gMovesInfo[gLastLandedMoves[battler]].power == 0) + if (gLastLandedMoves[battler] == MOVE_NONE) return FALSE; + if (gLastLandedMoves[battler] == MOVE_UNAVAILABLE) + return FALSE; + if (IS_MOVE_STATUS(gLastLandedMoves[battler])) + return FALSE; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { battlerIn1 = battler; @@ -105,96 +330,339 @@ static bool8 FindMonThatAbsorbsOpponentsMove(u32 battler) battlerIn1 = battler; battlerIn2 = battler; } + + // Create an array of possible absorb abilities so the AI considers all of them if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_FIRE) - absorbingTypeAbility = ABILITY_FLASH_FIRE; - else if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_WATER) - absorbingTypeAbility = ABILITY_WATER_ABSORB; - else if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_ELECTRIC) - absorbingTypeAbility = ABILITY_VOLT_ABSORB; - else - return FALSE; - if (gBattleMons[battler].ability == absorbingTypeAbility) - return FALSE; - for (i = 0; i < PARTY_SIZE; ++i) { - u16 species; + absorbingTypeAbilities[0] = ABILITY_FLASH_FIRE; + numAbsorbingAbilities = 1; + } + else if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_WATER) + { + absorbingTypeAbilities[0] = ABILITY_WATER_ABSORB; + absorbingTypeAbilities[1] = ABILITY_STORM_DRAIN; + absorbingTypeAbilities[2] = ABILITY_DRY_SKIN; + numAbsorbingAbilities = 3; + } + else if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_ELECTRIC) + { + absorbingTypeAbilities[0] = ABILITY_VOLT_ABSORB; + absorbingTypeAbilities[1] = ABILITY_MOTOR_DRIVE; + absorbingTypeAbilities[2] = ABILITY_LIGHTNING_ROD; + numAbsorbingAbilities = 3; + } + else if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_GRASS) + { + absorbingTypeAbilities[0] = ABILITY_SAP_SIPPER; + numAbsorbingAbilities = 1; + } + else if (gMovesInfo[gLastLandedMoves[battler]].type == TYPE_GROUND) + { + absorbingTypeAbilities[0] = ABILITY_EARTH_EATER; + numAbsorbingAbilities = 1; + } + else + { + return FALSE; + } + + // Check current mon for all absorbing abilities + for (i = 0; i < numAbsorbingAbilities; i++) + { + if (AI_DATA->abilities[battler] == absorbingTypeAbilities[i]) + return FALSE; + } + + GetAIPartyIndexes(battler, &firstId, &lastId); + + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = firstId; i < lastId; i++) + { u16 monAbility; - if ((GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) - || (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE) - || (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) - || (i == gBattlerPartyIndexes[battlerIn1]) - || (i == gBattlerPartyIndexes[battlerIn2]) - || (i == *(gBattleStruct->monToSwitchIntoId + battlerIn1)) - || (i == *(gBattleStruct->monToSwitchIntoId + battlerIn2))) + if (!IsValidForBattle(&party[i])) continue; - species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES); - if (GetMonData(&gEnemyParty[i], MON_DATA_ABILITY_NUM) != ABILITY_NONE) - monAbility = gSpeciesInfo[species].abilities[1]; - else - monAbility = gSpeciesInfo[species].abilities[0]; - if (absorbingTypeAbility == monAbility && Random() & 1) + if (i == gBattlerPartyIndexes[battlerIn1]) + continue; + if (i == gBattlerPartyIndexes[battlerIn2]) + continue; + if (i == gBattleStruct->monToSwitchIntoId[battlerIn1]) + continue; + if (i == gBattleStruct->monToSwitchIntoId[battlerIn2]) + continue; + if (IsAceMon(battler, i)) + continue; + + monAbility = GetMonAbility(&party[i]); + + for (j = 0; j < numAbsorbingAbilities; j++) { - // we found a mon - *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = i; - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); - return TRUE; + if (absorbingTypeAbilities[j] == monAbility && Random() & 1) + { + // we found a mon. + gBattleStruct->AI_monToSwitchIntoId[battler] = i; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + return TRUE; + } } } return FALSE; } -static bool8 ShouldSwitchIfNaturalCure(u32 battler) +static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult) { - if (!(gBattleMons[battler].status1 & STATUS1_SLEEP) - || (gBattleMons[battler].ability != ABILITY_NATURAL_CURE) - || (gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2)) + bool32 switchMon = FALSE; + bool32 monIdChosen = FALSE; // Id of the mon to switch into. + u16 monAbility = AI_DATA->abilities[battler]; + u16 holdEffect = AI_DATA->holdEffects[battler]; + u8 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); + u8 opposingBattler = GetBattlerAtPosition(opposingPosition); + s32 moduloChance = 4; //25% Chance Default + s32 chanceReducer = 1; //No Reduce default. Increase to reduce + s32 firstId; + s32 lastId; + s32 i; + struct Pokemon *party; + + if (AnyStatIsRaised(battler)) + chanceReducer = 5; // Reduce switchout probability by factor of 5 if setup + + //Perish Song + if (gStatuses3[battler] & STATUS3_PERISH_SONG + && gDisableStructs[battler].perishSongTimer == 0 + && monAbility != ABILITY_SOUNDPROOF) + switchMon = TRUE; + + if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING) + { + //Yawn + if (gStatuses3[battler] & STATUS3_YAWN + && AI_CanSleep(battler, monAbility) + && gBattleMons[battler].hp > gBattleMons[battler].maxHP / 3) + { + switchMon = TRUE; + + //Double Battles + //Check if partner can prevent sleep + if (IsDoubleBattle()) + { + if (IsBattlerAlive(BATTLE_PARTNER(battler)) + && (GetAIChosenMove(BATTLE_PARTNER(battler)) == MOVE_UPROAR) + ) + switchMon = FALSE; + + if (IsBattlerAlive(BATTLE_PARTNER(battler)) + && (gMovesInfo[AI_DATA->partnerMove].effect == EFFECT_MISTY_TERRAIN + || gMovesInfo[AI_DATA->partnerMove].effect == EFFECT_ELECTRIC_TERRAIN) + && IsBattlerGrounded(battler) + ) + switchMon = FALSE; + + if (*(gBattleStruct->AI_monToSwitchIntoId + BATTLE_PARTNER(battler)) != PARTY_SIZE) //Partner is switching + { + GetAIPartyIndexes(battler, &firstId, &lastId); + + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + party = gPlayerParty; + + for (i = firstId; i < lastId; i++) + { + if (IsAceMon(battler, i)) + continue; + + //Look for mon in party that is able to be switched into and has ability that sets terrain + if (IsValidForBattle(&party[i]) + && i != gBattlerPartyIndexes[battler] + && i != gBattlerPartyIndexes[BATTLE_PARTNER(battler)] + && IsBattlerGrounded(battler) + && (GetMonAbility(&party[i]) == ABILITY_MISTY_SURGE + || GetMonAbility(&party[i]) == ABILITY_ELECTRIC_SURGE)) //Ally has Misty or Electric Surge + { + *(gBattleStruct->AI_monToSwitchIntoId + BATTLE_PARTNER(battler)) = i; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SWITCH, 0); + switchMon = FALSE; + break; + } + } + } + } + + //Check if Active Pokemon can KO opponent instead of switching + //Will still fall asleep, but take out opposing Pokemon first + if (AiExpectsToFaintPlayer(battler)) + switchMon = FALSE; + + //Checks to see if active Pokemon can do something against sleep + if ((monAbility == ABILITY_NATURAL_CURE + || monAbility == ABILITY_SHED_SKIN + || monAbility == ABILITY_EARLY_BIRD) + || holdEffect == (HOLD_EFFECT_CURE_SLP | HOLD_EFFECT_CURE_STATUS) + || HasMove(battler, MOVE_SLEEP_TALK) + || (HasMoveEffect(battler, MOVE_SNORE) && AI_GetTypeEffectiveness(MOVE_SNORE, battler, opposingBattler) >= UQ_4_12(1.0)) + || (IsBattlerGrounded(battler) + && (HasMove(battler, MOVE_MISTY_TERRAIN) || HasMove(battler, MOVE_ELECTRIC_TERRAIN))) + ) + switchMon = FALSE; + + //Check if Active Pokemon evasion boosted and might be able to dodge until awake + if (gBattleMons[battler].statStages[STAT_EVASION] > (DEFAULT_STAT_STAGE + 3) + && AI_DATA->abilities[opposingBattler] != ABILITY_UNAWARE + && AI_DATA->abilities[opposingBattler] != ABILITY_KEEN_EYE + && AI_DATA->abilities[opposingBattler] != ABILITY_MINDS_EYE + && (B_ILLUMINATE_EFFECT >= GEN_9 && AI_DATA->abilities[opposingBattler] != ABILITY_ILLUMINATE) + && !(gBattleMons[battler].status2 & STATUS2_FORESIGHT) + && !(gStatuses3[battler] & STATUS3_MIRACLE_EYED)) + switchMon = FALSE; + + } + + //Secondary Damage + if (monAbility != ABILITY_MAGIC_GUARD + && !AiExpectsToFaintPlayer(battler)) + { + //Toxic + moduloChance = 2; //50% + if (((gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >= STATUS1_TOXIC_TURN(2)) + && gBattleMons[battler].hp >= (gBattleMons[battler].maxHP / 3) + && (Random() % (moduloChance*chanceReducer)) == 0) + switchMon = TRUE; + + //Cursed + moduloChance = 2; //50% + if (gBattleMons[battler].status2 & STATUS2_CURSED + && (Random() % (moduloChance*chanceReducer)) == 0) + switchMon = TRUE; + + //Nightmare + moduloChance = 3; //33.3% + if (gBattleMons[battler].status2 & STATUS2_NIGHTMARE + && (Random() % (moduloChance*chanceReducer)) == 0) + switchMon = TRUE; + + //Leech Seed + moduloChance = 4; //25% + if (gStatuses3[battler] & STATUS3_LEECHSEED + && (Random() % (moduloChance*chanceReducer)) == 0) + switchMon = TRUE; + } + + //Infatuation + if (gBattleMons[battler].status2 & STATUS2_INFATUATION + && !AiExpectsToFaintPlayer(battler)) + switchMon = TRUE; + + //Todo + //Pass Wish Heal + + //Semi-Invulnerable + if (gStatuses3[opposingBattler] & STATUS3_SEMI_INVULNERABLE) + { + if (FindMonThatAbsorbsOpponentsMove(battler, FALSE)) // Switch if absorber found. Note: FindMonThatAbsorbsOpponentsMove already provides id of the mon to switch into to gBattleStruct->AI_monToSwitchIntoId. + switchMon = TRUE, monIdChosen = TRUE; + if (!AI_OpponentCanFaintAiWithMod(battler, 0) + && AnyStatIsRaised(battler)) + switchMon = FALSE; + if (AiExpectsToFaintPlayer(battler) + && !AI_STRIKES_FIRST(battler, opposingBattler, 0) + && !AI_OpponentCanFaintAiWithMod(battler, 0)) + switchMon = FALSE; + } + } + + if (switchMon) + { + if (!monIdChosen) + gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SWITCH, 0); + return TRUE; + } + else + { return FALSE; - if ((gLastLandedMoves[battler] == MOVE_NONE || gLastLandedMoves[battler] == 0xFFFF) && Random() & 1) - { - *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = PARTY_SIZE; - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); - return TRUE; } - else if (gMovesInfo[gLastLandedMoves[battler]].power == 0 && Random() & 1) - { - *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = PARTY_SIZE; - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); - return TRUE; - } - if (FindMonWithFlagsAndSuperEffective(battler, MOVE_RESULT_DOESNT_AFFECT_FOE, 1) - || FindMonWithFlagsAndSuperEffective(battler, MOVE_RESULT_NOT_VERY_EFFECTIVE, 1)) - return TRUE; - if (Random() & 1) - { - *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = PARTY_SIZE; - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); - return TRUE; - } - return FALSE; } -static bool8 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool8 noRng) +static bool32 ShouldSwitchIfAbilityBenefit(u32 battler, bool32 emitResult) +{ + s32 moduloChance = 4; //25% Chance Default + s32 chanceReducer = 1; //No Reduce default. Increase to reduce + + if (AnyStatIsRaised(battler)) + chanceReducer = 5; // Reduce switchout probability by factor of 5 if setup + + //Check if ability is blocked + if (gStatuses3[battler] & STATUS3_GASTRO_ACID + ||IsNeutralizingGasOnField()) + return FALSE; + + switch(AI_DATA->abilities[battler]) + { + case ABILITY_NATURAL_CURE: + moduloChance = 4; //25% + //Attempt to cure bad ailment + if (gBattleMons[battler].status1 & (STATUS1_SLEEP | STATUS1_FREEZE | STATUS1_TOXIC_POISON) + && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE) + break; + //Attempt to cure lesser ailment + if ((gBattleMons[battler].status1 & STATUS1_ANY) + && (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2) + && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE + && Random() % (moduloChance*chanceReducer) == 0) + break; + + return FALSE; + + case ABILITY_REGENERATOR: + moduloChance = 2; //50% + //Don't switch if ailment + if (gBattleMons[battler].status1 & STATUS1_ANY) + return FALSE; + if ((gBattleMons[battler].hp <= ((gBattleMons[battler].maxHP * 2) / 3)) + && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE + && Random() % (moduloChance*chanceReducer) == 0) + break; + + return FALSE; + + default: + return FALSE; + } + + gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SWITCH, 0); + + return TRUE; +} + +static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng) { s32 i; - u8 moveFlags; u16 move; - + u32 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); - u32 opposingBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + u32 opposingBattler = GetBattlerAtPosition(opposingPosition); if (!(gAbsentBattlerFlags & gBitTable[opposingBattler])) { - for (i = 0; i < MAX_MON_MOVES; ++i) + for (i = 0; i < MAX_MON_MOVES; i++) { move = gBattleMons[battler].moves[i]; if (move == MOVE_NONE) continue; - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE) + if (AI_GetTypeEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0)) { - if (noRng || (Random() % 10)) + if (noRng) + return TRUE; + if (Random() % 10 != 0) return TRUE; } } @@ -206,13 +674,13 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool8 noRng) if (!(gAbsentBattlerFlags & gBitTable[opposingBattler])) { - for (i = 0; i < MAX_MON_MOVES; ++i) + for (i = 0; i < MAX_MON_MOVES; i++) { move = gBattleMons[battler].moves[i]; if (move == MOVE_NONE) continue; - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE) + + if (AI_GetTypeEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0)) { if (noRng) return TRUE; @@ -221,35 +689,42 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool8 noRng) } } } + return FALSE; } -static bool8 AreStatsRaised(u32 battler) +static bool32 AreStatsRaised(u32 battler) { u8 buffedStatsValue = 0; s32 i; - for (i = 0; i < NUM_BATTLE_STATS; ++i) + for (i = 0; i < NUM_BATTLE_STATS; i++) { - if (gBattleMons[battler].statStages[i] > 6) - buffedStatsValue += gBattleMons[battler].statStages[i] - 6; + if (gBattleMons[battler].statStages[i] > DEFAULT_STAT_STAGE) + buffedStatsValue += gBattleMons[battler].statStages[i] - DEFAULT_STAT_STAGE; } + return (buffedStatsValue > 3); } -static bool8 FindMonWithFlagsAndSuperEffective(u32 battler, u8 flags, u8 moduloPercent) +static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 moduloPercent, bool32 emitResult) { - u8 battlerIn1, battlerIn2; + u32 battlerIn1, battlerIn2; + s32 firstId; + s32 lastId; // + 1 + struct Pokemon *party; s32 i, j; u16 move; - u8 moveFlags; - if (gLastLandedMoves[battler] == 0) + if (gLastLandedMoves[battler] == MOVE_NONE) return FALSE; - if ((gLastLandedMoves[battler] == 0xFFFF) - || (gLastHitBy[battler] == 0xFF) - || (gMovesInfo[gLastLandedMoves[battler]].power == 0)) + if (gLastLandedMoves[battler] == MOVE_UNAVAILABLE) return FALSE; + if (gLastHitBy[battler] == 0xFF) + return FALSE; + if (IS_MOVE_STATUS(gLastLandedMoves[battler])) + return FALSE; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { battlerIn1 = battler; @@ -263,138 +738,374 @@ static bool8 FindMonWithFlagsAndSuperEffective(u32 battler, u8 flags, u8 moduloP battlerIn1 = battler; battlerIn2 = battler; } - for (i = 0; i < PARTY_SIZE; ++i) - { - u16 species; - u16 monAbility; - if ((GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) - || (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE) - || (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) - || (i == gBattlerPartyIndexes[battlerIn1]) - || (i == gBattlerPartyIndexes[battlerIn2]) - || (i == *(gBattleStruct->monToSwitchIntoId + battlerIn1)) - || (i == *(gBattleStruct->monToSwitchIntoId + battlerIn2))) + GetAIPartyIndexes(battler, &firstId, &lastId); + + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = firstId; i < lastId; i++) + { + u16 species, monAbility; + + if (!IsValidForBattle(&party[i])) continue; - species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES); - if (GetMonData(&gEnemyParty[i], MON_DATA_ABILITY_NUM) != ABILITY_NONE) - monAbility = gSpeciesInfo[species].abilities[1]; - else - monAbility = gSpeciesInfo[species].abilities[0]; - moveFlags = AI_TypeCalc(gLastLandedMoves[battler], species, monAbility); - if (moveFlags & flags) + if (i == gBattlerPartyIndexes[battlerIn1]) + continue; + if (i == gBattlerPartyIndexes[battlerIn2]) + continue; + if (i == gBattleStruct->monToSwitchIntoId[battlerIn1]) + continue; + if (i == gBattleStruct->monToSwitchIntoId[battlerIn2]) + continue; + if (IsAceMon(battler, i)) + continue; + + species = GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG); + monAbility = GetMonAbility(&party[i]); + CalcPartyMonTypeEffectivenessMultiplier(gLastLandedMoves[battler], species, monAbility); + if (gMoveResultFlags & flags) { battlerIn1 = gLastHitBy[battler]; - for (j = 0; j < MAX_MON_MOVES; ++j) + + for (j = 0; j < MAX_MON_MOVES; j++) { - move = GetMonData(&gEnemyParty[i], MON_DATA_MOVE1 + j); - if (move == MOVE_NONE) + move = GetMonData(&party[i], MON_DATA_MOVE1 + j); + if (move == 0) continue; - moveFlags = AI_TypeCalc(move, gBattleMons[battlerIn1].species, gBattleMons[battlerIn1].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE && Random() % moduloPercent == 0) + + if (AI_GetTypeEffectiveness(move, battler, battlerIn1) >= UQ_4_12(2.0) && Random() % moduloPercent == 0) { - *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = i; - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + gBattleStruct->AI_monToSwitchIntoId[battler] = i; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SWITCH, 0); return TRUE; } } } } + return FALSE; } -static bool8 ShouldSwitch(u32 battler) +static bool32 CanMonSurviveHazardSwitchin(u32 battler) { - u8 battlerIn1, battlerIn2; + u32 battlerIn1, battlerIn2; + u32 hazardDamage = 0, battlerHp = gBattleMons[battler].hp; + u32 ability = GetBattlerAbility(battler), aiMove; + s32 firstId, lastId, i, j; + struct Pokemon *party; + + if (ability == ABILITY_REGENERATOR) + battlerHp = (battlerHp * 133) / 100; // Account for Regenerator healing + + hazardDamage = GetSwitchinHazardsDamage(battler, &gBattleMons[battler]); + + // Battler will faint to hazards, check to see if another mon can clear them + if (hazardDamage > battlerHp) + { + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + battlerIn1 = battler; + if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))]) + battlerIn2 = battler; + else + battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler))); + } + else + { + battlerIn1 = battler; + battlerIn2 = battler; + } + + GetAIPartyIndexes(battler, &firstId, &lastId); + party = GetBattlerParty(battler); + + for (i = firstId; i < lastId; i++) + { + if (!IsValidForBattle(&party[i])) + continue; + if (i == gBattlerPartyIndexes[battlerIn1]) + continue; + if (i == gBattlerPartyIndexes[battlerIn2]) + continue; + if (i == gBattleStruct->monToSwitchIntoId[battlerIn1]) + continue; + if (i == gBattleStruct->monToSwitchIntoId[battlerIn2]) + continue; + if (IsAceMon(battler, i)) + continue; + + for (j = 0; j < MAX_MON_MOVES; j++) + { + aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL); + if (aiMove == MOVE_RAPID_SPIN || aiMove == MOVE_DEFOG || aiMove == MOVE_MORTAL_SPIN || aiMove == MOVE_TIDY_UP) + { + // Have a mon that can clear the hazards, so switching out is okay + return TRUE; + } + } + } + // Faints to hazards and party can't clear them, don't switch out + return FALSE; + } + return TRUE; +} + +static bool32 ShouldSwitchIfEncored(u32 battler, bool32 emitResult) +{ + // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer + if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) + return FALSE; + + // If not Encored or if no good switchin, don't switch + if (gDisableStructs[battler].encoredMove == MOVE_NONE || AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE) + return FALSE; + + // Otherwise 50% chance to switch out + if (Random() & 1) + { + gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; + if (emitResult) + BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + return TRUE; + } + + return FALSE; +} + +// AI should switch if it's become setup fodder and has something better to switch to +static bool32 AreAttackingStatsLowered(u32 battler, bool32 emitResult) +{ + s8 attackingStage = gBattleMons[battler].statStages[STAT_ATK]; + s8 spAttackingStage = gBattleMons[battler].statStages[STAT_SPATK]; + + // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer + if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) + return FALSE; + + // Physical attacker + if (gBattleMons[battler].attack > gBattleMons[battler].spAttack) + { + // Don't switch if attack isn't below -1 + if (attackingStage > DEFAULT_STAT_STAGE - 2) + return FALSE; + // 50% chance if attack at -2 and have a good candidate mon + else if (attackingStage == DEFAULT_STAT_STAGE - 2) + { + if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (Random() & 1)) + { + gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; + BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + return TRUE; + } + } + // If at -3 or worse, switch out regardless + else if (attackingStage < DEFAULT_STAT_STAGE - 2) + { + gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; + BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + return TRUE; + } + } + + // Special attacker + else + { + // Don't switch if attack isn't below -1 + if (spAttackingStage > DEFAULT_STAT_STAGE - 2) + return FALSE; + // 50% chance if attack at -2 and have a good candidate mon + else if (spAttackingStage == DEFAULT_STAT_STAGE - 2) + { + if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (Random() & 1)) + { + gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; + BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + return TRUE; + } + } + // If at -3 or worse, switch out regardless + else if (spAttackingStage < DEFAULT_STAT_STAGE - 2) + { + gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; + BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); + return TRUE; + } + } + return FALSE; +} + +bool32 ShouldSwitch(u32 battler, bool32 emitResult) +{ + u32 battlerIn1, battlerIn2; + s32 firstId; + s32 lastId; // + 1 + struct Pokemon *party; s32 i; s32 availableToSwitch; + bool32 hasAceMon = FALSE; + + if (gBattleMons[battler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + return FALSE; + if (gStatuses3[battler] & STATUS3_ROOTED) + return FALSE; + if (IsAbilityPreventingEscape(battler)) + return FALSE; - if ((gBattleMons[battler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) - || (gStatuses3[battler] & STATUS3_ROOTED) - || AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, battler, ABILITY_SHADOW_TAG, 0, 0) - || AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, battler, ABILITY_ARENA_TRAP, 0, 0)) - return FALSE; // misses the flying or levitate check - if (AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_MAGNET_PULL, 0, 0)) - if ((gBattleMons[battler].type1 == TYPE_STEEL) || (gBattleMons[battler].type2 == TYPE_STEEL)) - return FALSE; availableToSwitch = 0; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { battlerIn1 = battler; - if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(GetBattlerPosition(battler) ^ BIT_FLANK)]) + if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))]) battlerIn2 = battler; else - battlerIn2 = GetBattlerAtPosition(GetBattlerPosition(battler) ^ BIT_FLANK); + battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler))); } else { - battlerIn2 = battler; battlerIn1 = battler; + battlerIn2 = battler; } - for (i = 0; i < PARTY_SIZE; ++i) + + GetAIPartyIndexes(battler, &firstId, &lastId); + + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = firstId; i < lastId; i++) { - if ((GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) - || (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE) - || (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) - || (i == gBattlerPartyIndexes[battlerIn1]) - || (i == gBattlerPartyIndexes[battlerIn2]) - || (i == *(gBattleStruct->monToSwitchIntoId + battlerIn1)) - || (i == *(gBattleStruct->monToSwitchIntoId + battlerIn2))) + if (!IsValidForBattle(&party[i])) continue; - ++availableToSwitch; + if (i == gBattlerPartyIndexes[battlerIn1]) + continue; + if (i == gBattlerPartyIndexes[battlerIn2]) + continue; + if (i == gBattleStruct->monToSwitchIntoId[battlerIn1]) + continue; + if (i == gBattleStruct->monToSwitchIntoId[battlerIn2]) + continue; + if (IsAceMon(battler, i)) + { + hasAceMon = TRUE; + continue; + } + + availableToSwitch++; } - if (!availableToSwitch) - return FALSE; - if (ShouldSwitchIfPerishSong(battler) - || ShouldSwitchIfWonderGuard(battler) - || FindMonThatAbsorbsOpponentsMove(battler) - || ShouldSwitchIfNaturalCure(battler)) + + if (availableToSwitch == 0) + { + if (hasAceMon) // If the ace mon is the only available mon, use it + availableToSwitch++; + else + return FALSE; + } + + //NOTE: The sequence of the below functions matter! Do not change unless you have carefully considered the outcome. + //Since the order is sequencial, and some of these functions prompt switch to specific party members. + + //These Functions can prompt switch to specific party members + if (ShouldSwitchIfWonderGuard(battler, emitResult)) return TRUE; - if (HasSuperEffectiveMoveAgainstOpponents(battler, FALSE) - || AreStatsRaised(battler)) - return FALSE; - if (FindMonWithFlagsAndSuperEffective(battler, MOVE_RESULT_DOESNT_AFFECT_FOE, 2) - || FindMonWithFlagsAndSuperEffective(battler, MOVE_RESULT_NOT_VERY_EFFECTIVE, 3)) + if (ShouldSwitchIfGameStatePrompt(battler, emitResult)) return TRUE; + if (FindMonThatAbsorbsOpponentsMove(battler, emitResult)) + return TRUE; + + //These Functions can prompt switch to generic pary members + if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE)) + return FALSE; + if (ShouldSwitchIfAllBadMoves(battler, emitResult)) + return TRUE; + if (ShouldSwitchIfAbilityBenefit(battler, emitResult)) + return TRUE; + if (HasBadOdds(battler, emitResult)) + return TRUE; + if (ShouldSwitchIfEncored(battler, emitResult)) + return TRUE; + if (AreAttackingStatsLowered(battler, emitResult)) + return TRUE; + + // Removing switch capabilites under specific conditions + // These Functions prevent the "FindMonWithFlagsAndSuperEffective" from getting out of hand. + if (HasSuperEffectiveMoveAgainstOpponents(battler, FALSE)) + return FALSE; + if (AreStatsRaised(battler)) + return FALSE; + + //Default Function + //Can prompt switch if AI has a pokemon in party that resists current opponent & has super effective move + if (FindMonWithFlagsAndSuperEffective(battler, MOVE_RESULT_DOESNT_AFFECT_FOE, 2, emitResult) + || FindMonWithFlagsAndSuperEffective(battler, MOVE_RESULT_NOT_VERY_EFFECTIVE, 3, emitResult)) + return TRUE; + return FALSE; } void AI_TrySwitchOrUseItem(u32 battler) { + struct Pokemon *party; u8 battlerIn1, battlerIn2; + s32 firstId; + s32 lastId; // + 1 + u8 battlerPosition = GetBattlerPosition(battler); + + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { - if (ShouldSwitch(battler)) + if (ShouldSwitch(battler, TRUE)) { - if (*(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) == 6) + if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE) { - s32 monToSwitchId = GetMostSuitableMonToSwitchInto(battler); - if (monToSwitchId == 6) + s32 monToSwitchId = AI_DATA->mostSuitableMonId[battler]; + if (monToSwitchId == PARTY_SIZE) { if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) { - battlerIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + battlerIn1 = GetBattlerAtPosition(battlerPosition); battlerIn2 = battlerIn1; } else { - battlerIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - battlerIn2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + battlerIn1 = GetBattlerAtPosition(battlerPosition); + battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(battlerPosition)); } - for (monToSwitchId = 0; monToSwitchId < PARTY_SIZE; ++monToSwitchId) + + GetAIPartyIndexes(battler, &firstId, &lastId); + + for (monToSwitchId = (lastId-1); monToSwitchId >= firstId; monToSwitchId--) { - if ((!GetMonData(&gEnemyParty[monToSwitchId], MON_DATA_HP) == 0) - && (monToSwitchId != gBattlerPartyIndexes[battlerIn1]) - && (monToSwitchId != gBattlerPartyIndexes[battlerIn2]) - && (monToSwitchId != *(gBattleStruct->monToSwitchIntoId + battlerIn1)) - && (monToSwitchId != *(gBattleStruct->monToSwitchIntoId + battlerIn2))) - break; + if (!IsValidForBattle(&party[monToSwitchId])) + continue; + if (monToSwitchId == gBattlerPartyIndexes[battlerIn1]) + continue; + if (monToSwitchId == gBattlerPartyIndexes[battlerIn2]) + continue; + if (monToSwitchId == gBattleStruct->monToSwitchIntoId[battlerIn1]) + continue; + if (monToSwitchId == gBattleStruct->monToSwitchIntoId[battlerIn2]) + continue; + if (IsAceMon(battler, monToSwitchId)) + continue; + + break; } } - *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = monToSwitchId; + + gBattleStruct->AI_monToSwitchIntoId[battler] = monToSwitchId; } - *(gBattleStruct->monToSwitchIntoId + battler) = *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)); + + *(gBattleStruct->monToSwitchIntoId + battler) = gBattleStruct->AI_monToSwitchIntoId[battler]; return; } else if (ShouldUseItem(battler)) @@ -402,171 +1113,943 @@ void AI_TrySwitchOrUseItem(u32 battler) return; } } - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_USE_MOVE, (battler ^ BIT_SIDE) << 8); + + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_USE_MOVE, BATTLE_OPPOSITE(battler) << 8); } -static void ModulateByTypeEffectiveness(u8 atkType, u8 defType1, u8 defType2, u8 *var) +// If there are two(or more) mons to choose from, always choose one that has baton pass +// as most often it can't do much on its own. +static u32 GetBestMonBatonPass(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, int aliveCount, u32 battler, u32 opposingBattler) { - s32 i = 0; + int i, j, bits = 0; - *var = (*var * gTypeEffectivenessTable[atkType][defType1]); - *var = (*var * gTypeEffectivenessTable[atkType][defType2]); + for (i = firstId; i < lastId; i++) + { + if (invalidMons & gBitTable[i]) + continue; + + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL) == MOVE_BATON_PASS) + { + bits |= gBitTable[i]; + break; + } + } + } + + if ((aliveCount == 2 || (aliveCount > 2 && Random() % 3 == 0)) && bits) + { + do + { + i = (Random() % (lastId - firstId)) + firstId; + } while (!(bits & gBitTable[i])); + return i; + } + + return PARTY_SIZE; } -u8 GetMostSuitableMonToSwitchInto(u32 battler) +static u32 GetBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 battler, u32 opposingBattler) { - u8 opposingBattler; - u8 bestDmg; // Note : should be changed to u32 for obvious reasons. - u8 bestMonId; - u8 battlerIn1, battlerIn2; - s32 i, j; - u8 invalidMons; - u16 move; + int i, bits = 0; + + while (bits != 0x3F) // All mons were checked. + { + uq4_12_t bestResist = UQ_4_12(1.0); + int bestMonId = PARTY_SIZE; + // Find the mon whose type is the most suitable defensively. + for (i = firstId; i < lastId; i++) + { + if (!(gBitTable[i] & invalidMons) && !(gBitTable[i] & bits)) + { + u16 species = GetMonData(&party[i], MON_DATA_SPECIES); + uq4_12_t typeEffectiveness = UQ_4_12(1.0); + + u8 atkType1 = gBattleMons[opposingBattler].type1; + u8 atkType2 = gBattleMons[opposingBattler].type2; + u8 defType1 = gSpeciesInfo[species].types[0]; + u8 defType2 = gSpeciesInfo[species].types[1]; + + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType1))); + if (atkType2 != atkType1) + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType1))); + if (defType2 != defType1) + { + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType2))); + if (atkType2 != atkType1) + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType2))); + } + if (typeEffectiveness < bestResist) + { + bestResist = typeEffectiveness; + bestMonId = i; + } + } + } + + // Ok, we know the mon has the right typing but does it have at least one super effective move? + if (bestMonId != PARTY_SIZE) + { + for (i = 0; i < MAX_MON_MOVES; i++) + { + u32 move = GetMonData(&party[bestMonId], MON_DATA_MOVE1 + i); + if (move != MOVE_NONE && AI_GetTypeEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0)) + break; + } + + if (i != MAX_MON_MOVES) + return bestMonId; // Has both the typing and at least one super effective move. + + bits |= gBitTable[bestMonId]; // Sorry buddy, we want something better. + } + else + { + bits = 0x3F; // No viable mon to switch. + } + } + + return PARTY_SIZE; +} + +static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 battler, u32 opposingBattler) +{ + int i, j; + int dmg, bestDmg = 0; + int bestMonId = PARTY_SIZE; + u32 aiMove; + + gMoveResultFlags = 0; + // If we couldn't find the best mon in terms of typing, find the one that deals most damage. + for (i = firstId; i < lastId; i++) + { + if (gBitTable[i] & invalidMons) + continue; + InitializeSwitchinCandidate(&party[i]); + for (j = 0; j < MAX_MON_MOVES; j++) + { + aiMove = AI_DATA->switchinCandidate.battleMon.moves[j]; + if (aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0) + { + aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j); + dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE); + if (bestDmg < dmg) + { + bestDmg = dmg; + bestMonId = i; + } + } + } + } + + return bestMonId; +} + +static bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2) +{ + // List that makes mon not grounded + if (type1 == TYPE_FLYING || type2 == TYPE_FLYING || ability == ABILITY_LEVITATE + || (heldItemEffect == HOLD_EFFECT_AIR_BALLOON && ability != ABILITY_KLUTZ)) + { + // List that overrides being off the ground + if ((heldItemEffect == HOLD_EFFECT_IRON_BALL && ability != ABILITY_KLUTZ) || (gFieldStatuses & STATUS_FIELD_GRAVITY) || (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM)) + return TRUE; + else + return FALSE; + } + else + return TRUE; +} + +// Gets hazard damage +static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon) +{ + u8 defType1 = battleMon->type1, defType2 = battleMon->type2, tSpikesLayers; + u16 heldItemEffect = gItems[battleMon->item].holdEffect; + u32 maxHP = battleMon->maxHP, ability = battleMon->ability, status = battleMon->status1; + u32 spikesDamage = 0, tSpikesDamage = 0, hazardDamage = 0; + u32 hazardFlags = gSideStatuses[GetBattlerSide(battler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_SAFEGUARD); + + // Check ways mon might avoid all hazards + if (ability != ABILITY_MAGIC_GUARD || (heldItemEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS && + !((gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) || ability == ABILITY_KLUTZ))) + { + // Stealth Rock + if ((hazardFlags & SIDE_STATUS_STEALTH_ROCK) && heldItemEffect != HOLD_EFFECT_HEAVY_DUTY_BOOTS) + hazardDamage += GetStealthHazardDamageByTypesAndHP(gMovesInfo[MOVE_STEALTH_ROCK].type, defType1, defType2, battleMon->maxHP); + // Spikes + if ((hazardFlags & SIDE_STATUS_SPIKES) && IsMonGrounded(heldItemEffect, ability, defType1, defType2)) + { + spikesDamage = maxHP / ((5 - gSideTimers[GetBattlerSide(battler)].spikesAmount) * 2); + if (spikesDamage == 0) + spikesDamage = 1; + hazardDamage += spikesDamage; + } + + // Toxic Spikes + // TODO: CanBePoisoned compatibility to avoid duplicate code + if ((hazardFlags & SIDE_STATUS_TOXIC_SPIKES) && (defType1 != TYPE_POISON && defType2 != TYPE_POISON + && defType1 != TYPE_STEEL && defType2 != TYPE_STEEL + && ability != ABILITY_IMMUNITY && ability != ABILITY_POISON_HEAL && ability != ABILITY_COMATOSE + && status == 0 + && !(hazardFlags & SIDE_STATUS_SAFEGUARD) + && !(IsAbilityOnSide(battler, ABILITY_PASTEL_VEIL)) + && !(IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN)) + && !(IsAbilityStatusProtected(battler)) + && heldItemEffect != HOLD_EFFECT_CURE_PSN && heldItemEffect != HOLD_EFFECT_CURE_STATUS + && IsMonGrounded(heldItemEffect, ability, defType1, defType2))) + { + tSpikesLayers = gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount; + if (tSpikesLayers == 1) + { + tSpikesDamage = maxHP / 8; + if (tSpikesDamage == 0) + tSpikesDamage = 1; + } + else if (tSpikesLayers >= 2) + { + tSpikesDamage = maxHP / 16; + if (tSpikesDamage == 0) + tSpikesDamage = 1; + } + hazardDamage += tSpikesDamage; + } + } + return hazardDamage; +} + +// Gets damage / healing from weather +static s32 GetSwitchinWeatherImpact(void) +{ + s32 weatherImpact = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability; + u16 item = AI_DATA->switchinCandidate.battleMon.item; + + if (WEATHER_HAS_EFFECT) + { + // Damage + if (item != ITEM_SAFETY_GOGGLES) + { + if ((gBattleWeather & B_WEATHER_HAIL) && (AI_DATA->switchinCandidate.battleMon.type1 != TYPE_ICE || AI_DATA->switchinCandidate.battleMon.type2 != TYPE_ICE) + && ability != ABILITY_OVERCOAT && ability != ABILITY_SNOW_CLOAK && ability != ABILITY_ICE_BODY) + { + weatherImpact = maxHP / 16; + if (weatherImpact == 0) + weatherImpact = 1; + } + else if ((gBattleWeather & B_WEATHER_SANDSTORM) && (AI_DATA->switchinCandidate.battleMon.type1 != TYPE_GROUND && AI_DATA->switchinCandidate.battleMon.type2 != TYPE_GROUND + && AI_DATA->switchinCandidate.battleMon.type1 != TYPE_ROCK && AI_DATA->switchinCandidate.battleMon.type2 != TYPE_ROCK + && AI_DATA->switchinCandidate.battleMon.type1 != TYPE_STEEL && AI_DATA->switchinCandidate.battleMon.type2 != TYPE_STEEL + && ability != ABILITY_OVERCOAT && ability != ABILITY_SAND_VEIL && ability != ABILITY_SAND_RUSH && ability != ABILITY_SAND_FORCE)) + { + weatherImpact = maxHP / 16; + if (weatherImpact == 0) + weatherImpact = 1; + } + } + if ((gBattleWeather & B_WEATHER_SUN) && (ability == ABILITY_SOLAR_POWER || ability == ABILITY_DRY_SKIN)) + { + weatherImpact = maxHP / 8; + if (weatherImpact == 0) + weatherImpact = 1; + } + + // Healing + if (gBattleWeather & B_WEATHER_RAIN) + { + if (ability == ABILITY_DRY_SKIN) + { + weatherImpact = maxHP / 8; + if (weatherImpact == 0) + weatherImpact = 1; + } + else if (ability == ABILITY_RAIN_DISH) + { + weatherImpact = maxHP / 16; + if (weatherImpact == 0) + weatherImpact = 1; + } + } + if (((gBattleWeather & B_WEATHER_HAIL) || (gBattleWeather & B_WEATHER_SNOW)) && ability == ABILITY_ICE_BODY) + { + weatherImpact = maxHP / 16; + if (weatherImpact == 0) + weatherImpact =1; + } + } + return weatherImpact; +} + +// Gets one turn of recurring healing +static u32 GetSwitchinRecurringHealing(void) +{ + u32 recurringHealing = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability; + u16 item = AI_DATA->switchinCandidate.battleMon.item; + + // Items + if (ability != ABILITY_KLUTZ) + { + if (item == ITEM_BLACK_SLUDGE && (AI_DATA->switchinCandidate.battleMon.type1 == TYPE_POISON || AI_DATA->switchinCandidate.battleMon.type2 == TYPE_POISON)) + { + recurringHealing = maxHP / 16; + if (recurringHealing == 0) + recurringHealing = 1; + } + else if (item == ITEM_LEFTOVERS) + { + recurringHealing = maxHP / 16; + if (recurringHealing == 0) + recurringHealing = 1; + } + } // Intentionally omitting Shell Bell for its inconsistency + + // Abilities + if (ability == ABILITY_POISON_HEAL && (AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_POISON)) + { + recurringHealing = maxHP / 8; + if (recurringHealing == 0) + recurringHealing = 1; + } + return recurringHealing; +} + +// Gets one turn of recurring damage +static u32 GetSwitchinRecurringDamage(void) +{ + u32 passiveDamage = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability; + u16 item = AI_DATA->switchinCandidate.battleMon.item; + + // Items + if (ability != ABILITY_MAGIC_GUARD && ability != ABILITY_KLUTZ) + { + if (item == ITEM_BLACK_SLUDGE && AI_DATA->switchinCandidate.battleMon.type1 != TYPE_POISON && AI_DATA->switchinCandidate.battleMon.type2 != TYPE_POISON) + { + passiveDamage = maxHP / 8; + if (passiveDamage == 0) + passiveDamage = 1; + } + else if (item == ITEM_LIFE_ORB && ability != ABILITY_SHEER_FORCE) + { + passiveDamage = maxHP / 10; + if (passiveDamage == 0) + passiveDamage = 1; + } + else if (item == ITEM_STICKY_BARB) + { + passiveDamage = maxHP / 8; + if(passiveDamage == 0) + passiveDamage = 1; + } + } + return passiveDamage; +} + +// Gets one turn of status damage +static u32 GetSwitchinStatusDamage(u32 battler) +{ + u8 defType1 = AI_DATA->switchinCandidate.battleMon.type1, defType2 = AI_DATA->switchinCandidate.battleMon.type2; + u8 tSpikesLayers = gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount; + u16 heldItemEffect = gItems[AI_DATA->switchinCandidate.battleMon.item].holdEffect; + u32 status = AI_DATA->switchinCandidate.battleMon.status1, ability = AI_DATA->switchinCandidate.battleMon.ability, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP; + u32 statusDamage = 0; + + // Status condition damage + if ((status != 0) && AI_DATA->switchinCandidate.battleMon.ability != ABILITY_MAGIC_GUARD) + { + if (status & STATUS1_BURN) + { + if (B_BURN_DAMAGE >= GEN_7) + statusDamage = maxHP / 16; + else + statusDamage = maxHP / 8; + if(ability == ABILITY_HEATPROOF) + statusDamage = statusDamage / 2; + if (statusDamage == 0) + statusDamage = 1; + } + else if (status & STATUS1_FROSTBITE) + { + if (B_BURN_DAMAGE >= GEN_7) + statusDamage = maxHP / 16; + else + statusDamage = maxHP / 8; + if (statusDamage == 0) + statusDamage = 1; + } + else if ((status & STATUS1_POISON) && ability != ABILITY_POISON_HEAL) + { + statusDamage = maxHP / 8; + if (statusDamage == 0) + statusDamage = 1; + } + else if ((status & STATUS1_TOXIC_POISON) && ability != ABILITY_POISON_HEAL) + { + if ((status & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_TURN(15)) // not 16 turns + AI_DATA->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1); + statusDamage *= AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_COUNTER >> 8; + if (statusDamage == 0) + statusDamage = 1; + } + } + + // Apply hypothetical poisoning from Toxic Spikes, which means the first turn of damage already added in GetSwitchinHazardsDamage + // Do this last to skip one iteration of Poison / Toxic damage, and start counting Toxic damage one turn later. + if (tSpikesLayers != 0 && (defType1 != TYPE_POISON && defType2 != TYPE_POISON + && ability != ABILITY_IMMUNITY && ability != ABILITY_POISON_HEAL + && status == 0 + && !(heldItemEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS + && (((gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) || ability == ABILITY_KLUTZ))) + && heldItemEffect != HOLD_EFFECT_CURE_PSN && heldItemEffect != HOLD_EFFECT_CURE_STATUS + && IsMonGrounded(heldItemEffect, ability, defType1, defType2))) + { + if (tSpikesLayers == 1) + { + AI_DATA->switchinCandidate.battleMon.status1 = STATUS1_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes + AI_DATA->switchinCandidate.hypotheticalStatus = TRUE; + } + if (tSpikesLayers == 2) + { + AI_DATA->switchinCandidate.battleMon.status1 = STATUS1_TOXIC_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes + AI_DATA->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1); + AI_DATA->switchinCandidate.hypotheticalStatus = TRUE; + } + } + return statusDamage; +} + +// Gets number of hits to KO factoring in hazards, healing held items, status, and weather +static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler) +{ + u32 startingHP = AI_DATA->switchinCandidate.battleMon.hp - GetSwitchinHazardsDamage(battler, &AI_DATA->switchinCandidate.battleMon); + s32 weatherImpact = GetSwitchinWeatherImpact(); // Signed to handle both damage and healing in the same value + u32 recurringDamage = GetSwitchinRecurringDamage(); + u32 recurringHealing = GetSwitchinRecurringHealing(); + u32 statusDamage = GetSwitchinStatusDamage(battler); + u32 hitsToKO = 0, singleUseItemHeal = 0; + u16 maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, item = AI_DATA->switchinCandidate.battleMon.item, heldItemEffect = gItems[AI_DATA->switchinCandidate.battleMon.item].holdEffect; + u8 weatherDuration = gWishFutureKnock.weatherDuration, holdEffectParam = gItems[AI_DATA->switchinCandidate.battleMon.item].holdEffectParam; + u32 opposingBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(battler))); + u32 opposingAbility = gBattleMons[opposingBattler].ability; + bool32 usedSingleUseHealingItem = FALSE; + s32 currentHP = startingHP; + + // No damage being dealt + if ((damageTaken + statusDamage + recurringDamage <= recurringHealing) || damageTaken + statusDamage + recurringDamage == 0) + return startingHP; + + // Mon fainted to hazards + if (startingHP == 0) + return 1; + + // Find hits to KO + while (currentHP > 0) + { + // Remove weather damage when it would run out + if (weatherImpact != 0 && weatherDuration == 0) + weatherImpact = 0; + + // Take attack damage for the turn + currentHP = currentHP - damageTaken; + + // If mon is still alive, apply weather impact first, as it might KO the mon before it can heal with its item (order is weather -> item -> status) + if (currentHP != 0) + currentHP = currentHP + weatherImpact; + + // Check if we're at a single use healing item threshold + if (AI_DATA->switchinCandidate.battleMon.ability != ABILITY_KLUTZ && usedSingleUseHealingItem == FALSE) + { + if (currentHP < maxHP / 2) + { + if (item == ITEM_BERRY_JUICE) + { + singleUseItemHeal = holdEffectParam; + } + else if (opposingAbility != ABILITY_UNNERVE && heldItemEffect == HOLD_EFFECT_RESTORE_HP) + { + // By default, this should only encompass Oran Berry and Sitrus Berry. + singleUseItemHeal = holdEffectParam; + if (singleUseItemHeal == 0) + singleUseItemHeal = 1; + } + } + else if (currentHP < maxHP / CONFUSE_BERRY_HP_FRACTION + && opposingAbility != ABILITY_UNNERVE + && (item == ITEM_AGUAV_BERRY || item == ITEM_FIGY_BERRY || item == ITEM_IAPAPA_BERRY || item == ITEM_MAGO_BERRY || item == ITEM_WIKI_BERRY)) + { + singleUseItemHeal = maxHP / CONFUSE_BERRY_HEAL_FRACTION; + if (singleUseItemHeal == 0) + singleUseItemHeal = 1; + } + + // If we used one, apply it without overcapping our maxHP + if (singleUseItemHeal > 0) + { + if ((currentHP + singleUseItemHeal) > maxHP) + currentHP = maxHP; + else + currentHP = currentHP + singleUseItemHeal; + usedSingleUseHealingItem = TRUE; + } + } + + // Healing from items occurs before status so we can do the rest in one line + if (currentHP >= 0) + currentHP = currentHP + recurringHealing - recurringDamage - statusDamage; + + // Recalculate toxic damage if needed + if (AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_POISON) + statusDamage = GetSwitchinStatusDamage(battler); + + // Reduce weather duration + if (weatherDuration != 0) + weatherDuration--; + + hitsToKO++; + } + + // If mon had a hypothetical status from TSpikes, clear it + if (AI_DATA->switchinCandidate.hypotheticalStatus == TRUE) + { + AI_DATA->switchinCandidate.battleMon.status1 = 0; + AI_DATA->switchinCandidate.hypotheticalStatus = FALSE; + } + return hitsToKO; +} + +static u16 GetSwitchinTypeMatchup(u32 opposingBattler, struct BattlePokemon battleMon) +{ + + // Check type matchup + u16 typeEffectiveness = UQ_4_12(1.0); + u8 atkType1 = gSpeciesInfo[gBattleMons[opposingBattler].species].types[0], atkType2 = gSpeciesInfo[gBattleMons[opposingBattler].species].types[1], + defType1 = battleMon.type1, defType2 = battleMon.type2; + + // Multiply type effectiveness by a factor depending on type matchup + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType1))); + if (atkType2 != atkType1) + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType1))); + if (defType2 != defType1) + { + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType2))); + if (atkType2 != atkType1) + typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType2))); + } + return typeEffectiveness; +} + +static int GetRandomSwitchinWithBatonPass(int aliveCount, int bits, int firstId, int lastId, int currentMonId) +{ + // Breakout early if there aren't any Baton Pass mons to save computation time + if (bits == 0) + return PARTY_SIZE; + + // GetBestMonBatonPass randomly chooses between all mons that met Baton Pass check + if ((aliveCount == 2 || (aliveCount > 2 && Random() % 3 == 0)) && bits) + { + do + { + return (Random() % (lastId - firstId)) + firstId; + } while (!(bits & gBitTable[currentMonId])); + } + + // Catch any other cases (such as only one mon alive and it has Baton Pass) + else + return PARTY_SIZE; +} + +static s32 GetMaxDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposingBattler, struct BattlePokemon battleMon) +{ + int i = 0; + u32 playerMove; + s32 damageTaken = 0, maxDamageTaken = 0; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + playerMove = gBattleMons[opposingBattler].moves[i]; + if (playerMove != MOVE_NONE && gMovesInfo[playerMove].power != 0) + { + damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, FALSE); + if (damageTaken > maxDamageTaken) + maxDamageTaken = damageTaken; + } + } + return maxDamageTaken; +} + +// This function splits switching behaviour mid-battle from after a KO. +// Mid battle, it integrates GetBestMonTypeMatchup (vanilla with modifications), GetBestMonDefensive (custom), and GetBestMonBatonPass (vanilla with modifications) +// After a KO, integrates GetBestMonRevengeKiller (custom), GetBestMonTypeMatchup (vanilla with modifications), GetBestMonBatonPass (vanilla with modifications), and GetBestMonDmg (vanilla) +// the Type Matchup code will prioritize switching into a mon with the best type matchup and also a super effective move, or just best type matchup if no super effective move is found +// the Most Defensive code will prioritize switching into the mon that takes the most hits to KO, with a minimum of 4 hits required to be considered a valid option +// the Baton Pass code will prioritize switching into a mon with Baton Pass if it can get in, boost, and BP out without being KO'd, and randomizes between multiple valid options +// the Revenge Killer code will prioritize, in order, OHKO and outspeeds / OHKO, slower but not 2HKO'd / 2HKO, outspeeds and not OHKO'd / 2HKO, slower but not 3HKO'd +// the Most Damage code will prioritize switching into whatever mon deals the most damage, which is generally not as good as having a good Type Matchup +// Everything runs in the same loop to minimize computation time. This makes it harder to read, but hopefully the comments can guide you! + +static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, u32 battler, u32 opposingBattler, u8 battlerIn1, u8 battlerIn2, bool32 isSwitchAfterKO) +{ + int revengeKillerId = PARTY_SIZE, slowRevengeKillerId = PARTY_SIZE, fastThreatenId = PARTY_SIZE, slowThreatenId = PARTY_SIZE, damageMonId = PARTY_SIZE; + int batonPassId = PARTY_SIZE, typeMatchupId = PARTY_SIZE, typeMatchupEffectiveId = PARTY_SIZE, defensiveMonId = PARTY_SIZE, aceMonId = PARTY_SIZE; + int i, j, aliveCount = 0, bits = 0; + s32 defensiveMonHitKOThreshold = 3; // 3HKO threshold that candidate defensive mons must exceed + u32 aiMove, hitsToKO, hitsToKOThreshold, maxHitsToKO = 0; + s32 playerMonSpeed = gBattleMons[opposingBattler].speed, playerMonHP = gBattleMons[opposingBattler].hp, aiMonSpeed, maxDamageDealt = 0, damageDealt = 0; + u16 bestResist = UQ_4_12(1.0), bestResistEffective = UQ_4_12(1.0), typeMatchup; + + if (isSwitchAfterKO) + hitsToKOThreshold = 1; // After a KO, mons at minimum need to not be 1-shot, as they switch in for free + else + hitsToKOThreshold = 2; // When switching in otherwise need to not be 2-shot, as they do not switch in for free + + // Iterate through mons + for (i = firstId; i < lastId; i++) + { + // Check mon validity + if (!IsValidForBattle(&party[i]) + || gBattlerPartyIndexes[battlerIn1] == i + || gBattlerPartyIndexes[battlerIn2] == i + || i == gBattleStruct->monToSwitchIntoId[battlerIn1] + || i == gBattleStruct->monToSwitchIntoId[battlerIn2]) + { + continue; + } + // Save Ace Pokemon for last + else if (IsAceMon(battler, i)) + { + aceMonId = i; + continue; + } + else + aliveCount++; + + InitializeSwitchinCandidate(&party[i]); + + // While not really invalid per say, not really wise to switch into this mon + if (AI_DATA->switchinCandidate.battleMon.ability == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler)) + continue; + + // Get max number of hits for player to KO AI mon + hitsToKO = GetSwitchinHitsToKO(GetMaxDamagePlayerCouldDealToSwitchin(battler, opposingBattler, AI_DATA->switchinCandidate.battleMon), battler); + + // Track max hits to KO and set GetBestMonDefensive if applicable + if(hitsToKO > maxHitsToKO) + { + maxHitsToKO = hitsToKO; + if(maxHitsToKO > defensiveMonHitKOThreshold) + defensiveMonId = i; + } + + typeMatchup = GetSwitchinTypeMatchup(opposingBattler, AI_DATA->switchinCandidate.battleMon); + + // Check that good type matchups gets at least two turns and set GetBestMonTypeMatchup if applicable + if (typeMatchup < bestResist) + { + if ((hitsToKO > hitsToKOThreshold && AI_DATA->switchinCandidate.battleMon.speed > playerMonSpeed) || hitsToKO > hitsToKOThreshold + 1) // Need to take an extra hit if slower + { + bestResist = typeMatchup; + typeMatchupId = i; + } + } + + aiMonSpeed = AI_DATA->switchinCandidate.battleMon.speed; + + // Check through current mon's moves + for (j = 0; j < MAX_MON_MOVES; j++) + { + aiMove = AI_DATA->switchinCandidate.battleMon.moves[j]; + + // Only do damage calc if switching after KO, don't need it otherwise and saves ~0.02s per turn + if (isSwitchAfterKO && aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0) + damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE); + + // Check for Baton Pass; hitsToKO requirements mean mon can boost and BP without dying whether it's slower or not + if (aiMove == MOVE_BATON_PASS && ((hitsToKO > hitsToKOThreshold + 1 && AI_DATA->switchinCandidate.battleMon.speed < playerMonSpeed) || (hitsToKO > hitsToKOThreshold && AI_DATA->switchinCandidate.battleMon.speed > playerMonSpeed))) + bits |= gBitTable[i]; + + // Check for mon with resistance and super effective move for GetBestMonTypeMatchup + if (aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0) + { + if (typeMatchup < bestResistEffective) + { + if (AI_GetTypeEffectiveness(aiMove, battler, opposingBattler) >= UQ_4_12(2.0)) + { + // Assuming a super effective move would do significant damage or scare the player out, so not being as conservative here + if (hitsToKO > hitsToKOThreshold) + { + bestResistEffective = typeMatchup; + typeMatchupEffectiveId = i; + } + } + } + + // If a self destruction move doesn't OHKO, don't factor it into revenge killing + if (gMovesInfo[aiMove].effect == EFFECT_EXPLOSION && damageDealt < playerMonHP) + continue; + + // Check that mon isn't one shot and set GetBestMonDmg if applicable + if (damageDealt > maxDamageDealt) + { + if(hitsToKO > hitsToKOThreshold) + { + maxDamageDealt = damageDealt; + damageMonId = i; + } + } + + // Check if current mon can revenge kill in some capacity + // If AI mon can one shot + if (damageDealt > playerMonHP) + { + // If AI mon is faster and doesn't die to hazards + if ((aiMonSpeed > playerMonSpeed || gMovesInfo[aiMove].priority > 0) && AI_DATA->switchinCandidate.battleMon.hp > GetSwitchinHazardsDamage(battler, &AI_DATA->switchinCandidate.battleMon)) + { + // We have a revenge killer + revengeKillerId = i; + } + + // If AI mon is slower + else + { + // If AI mon can't be OHKO'd + if (hitsToKO > hitsToKOThreshold) + { + // We have a slow revenge killer + slowRevengeKillerId = i; + } + } + } + + // If AI mon can two shot + if (damageDealt > playerMonHP / 2) + { + // If AI mon is faster + if (aiMonSpeed > playerMonSpeed || gMovesInfo[aiMove].priority > 0) + { + // If AI mon can't be OHKO'd + if (hitsToKO > hitsToKOThreshold) + { + // We have a fast threaten + fastThreatenId = i; + } + } + // If AI mon is slower + else + { + // If AI mon can't be 2HKO'd + if (hitsToKO > hitsToKOThreshold + 1) + { + // We have a slow threaten + slowThreatenId = i; + } + } + } + } + } + } + + batonPassId = GetRandomSwitchinWithBatonPass(aliveCount, bits, firstId, lastId, i); + + // Different switching priorities depending on switching mid battle vs switching after a KO + if (isSwitchAfterKO) + { + // Return GetBestMonRevengeKiller > GetBestMonTypeMatchup > GetBestMonBatonPass > GetBestMonDmg + if (revengeKillerId != PARTY_SIZE) + return revengeKillerId; + + else if (slowRevengeKillerId != PARTY_SIZE) + return slowRevengeKillerId; + + else if (fastThreatenId != PARTY_SIZE) + return fastThreatenId; + + else if (slowThreatenId != PARTY_SIZE) + return slowThreatenId; + + else if (typeMatchupEffectiveId != PARTY_SIZE) + return typeMatchupEffectiveId; + + else if (typeMatchupId != PARTY_SIZE) + return typeMatchupId; + + else if (batonPassId != PARTY_SIZE) + return batonPassId; + + else if (damageMonId != PARTY_SIZE) + return damageMonId; + } + else + { + // Return GetBestMonTypeMatchup > GetBestMonDefensive > GetBestMonBatonPass + if (typeMatchupEffectiveId != PARTY_SIZE) + return typeMatchupEffectiveId; + + else if (typeMatchupId != PARTY_SIZE) + return typeMatchupId; + + else if (defensiveMonId != PARTY_SIZE) + return defensiveMonId; + + else if (batonPassId != PARTY_SIZE) + return batonPassId; + + // If ace mon is the last available Pokemon and U-Turn/Volt Switch was used - switch to the mon. + else if (aceMonId != PARTY_SIZE + && (gMovesInfo[gLastUsedMove].effect == EFFECT_HIT_ESCAPE || gMovesInfo[gLastUsedMove].effect == EFFECT_PARTING_SHOT)) + return aceMonId; + } + return PARTY_SIZE; +} + +u8 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd) +{ + u32 opposingBattler = 0; + u32 bestMonId = PARTY_SIZE; + u8 battlerIn1 = 0, battlerIn2 = 0; + s32 firstId = 0; + s32 lastId = 0; // + 1 + struct Pokemon *party; if (*(gBattleStruct->monToSwitchIntoId + battler) != PARTY_SIZE) return *(gBattleStruct->monToSwitchIntoId + battler); + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { battlerIn1 = battler; - if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(GetBattlerPosition(battler) ^ BIT_FLANK)]) + if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))]) battlerIn2 = battler; else - battlerIn2 = GetBattlerAtPosition(GetBattlerPosition(battler) ^ BIT_FLANK); - // UB: It considers the opponent only player's side even though it can battle alongside player. - opposingBattler = Random() & BIT_FLANK; + battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler))); + + opposingBattler = BATTLE_OPPOSITE(battlerIn1); if (gAbsentBattlerFlags & gBitTable[opposingBattler]) opposingBattler ^= BIT_FLANK; } else { - opposingBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + opposingBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(battler))); battlerIn1 = battler; battlerIn2 = battler; } - invalidMons = 0; - while (invalidMons != 0x3F) // All mons are invalid. + + GetAIPartyIndexes(battler, &firstId, &lastId); + + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + // Split ideal mon decision between after previous mon KO'd (prioritize offensive options) and after switching active mon out (prioritize defensive options), and expand the scope of both. + // Only use better mon selection if AI_FLAG_SMART_MON_CHOICES is set for the trainer. + if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_MON_CHOICES && !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic { - bestDmg = 0; - bestMonId = 6; - // Find the mon whose type is the most suitable offensively. - for (i = 0; i < PARTY_SIZE; ++i) + bestMonId = GetBestMonIntegrated(party, firstId, lastId, battler, opposingBattler, battlerIn1, battlerIn2, switchAfterMonKOd); + return bestMonId; + } + + // This all handled by the GetBestMonIntegrated function if the AI_FLAG_SMART_MON_CHOICES flag is set + else + { + s32 i, aliveCount = 0; + u32 invalidMons = 0, aceMonId = PARTY_SIZE; + // Get invalid slots ids. + for (i = firstId; i < lastId; i++) { - u16 species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES); - if (species != SPECIES_NONE - && GetMonData(&gEnemyParty[i], MON_DATA_HP) != 0 - && !(gBitTable[i] & invalidMons) - && gBattlerPartyIndexes[battlerIn1] != i - && gBattlerPartyIndexes[battlerIn2] != i - && i != *(gBattleStruct->monToSwitchIntoId + battlerIn1) - && i != *(gBattleStruct->monToSwitchIntoId + battlerIn2)) - { - u8 type1 = gSpeciesInfo[species].types[0]; - u8 type2 = gSpeciesInfo[species].types[1]; - u8 typeDmg = 10; - ModulateByTypeEffectiveness(gBattleMons[opposingBattler].type1, type1, type2, &typeDmg); - ModulateByTypeEffectiveness(gBattleMons[opposingBattler].type2, type1, type2, &typeDmg); - if (bestDmg < typeDmg) - { - bestDmg = typeDmg; - bestMonId = i; - } - } - else + if (!IsValidForBattle(&party[i]) + || gBattlerPartyIndexes[battlerIn1] == i + || gBattlerPartyIndexes[battlerIn2] == i + || i == gBattleStruct->monToSwitchIntoId[battlerIn1] + || i == gBattleStruct->monToSwitchIntoId[battlerIn2] + || (GetMonAbility(&party[i]) == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler))) // While not really invalid per say, not really wise to switch into this mon.) { invalidMons |= gBitTable[i]; } + else if (IsAceMon(battler, i))// Save Ace Pokemon for last. + { + aceMonId = i; + invalidMons |= gBitTable[i]; + } + else + { + aliveCount++; + } } - // Ok, we know the mon has the right typing but does it have at least one super effective move? + bestMonId = GetBestMonBatonPass(party, firstId, lastId, invalidMons, aliveCount, battler, opposingBattler); if (bestMonId != PARTY_SIZE) - { - for (i = 0; i < MAX_MON_MOVES; ++i) - { - move = GetMonData(&gEnemyParty[bestMonId], MON_DATA_MOVE1 + i); - if (move != MOVE_NONE && TypeCalc(move, battler, opposingBattler) & MOVE_RESULT_SUPER_EFFECTIVE) - break; - } - if (i != MAX_MON_MOVES) - return bestMonId; // Has both the typing and at least one super effective move. + return bestMonId; - invalidMons |= gBitTable[bestMonId]; // Sorry buddy, we want something better. - } - else - { - invalidMons = 0x3F; // No viable mon to switch. - } + bestMonId = GetBestMonTypeMatchup(party, firstId, lastId, invalidMons, battler, opposingBattler); + if (bestMonId != PARTY_SIZE) + return bestMonId; + + bestMonId = GetBestMonDmg(party, firstId, lastId, invalidMons, battler, opposingBattler); + if (bestMonId != PARTY_SIZE) + return bestMonId; + + // If ace mon is the last available Pokemon and switch move was used - switch to the mon. + if (aceMonId != PARTY_SIZE) + return aceMonId; + + return PARTY_SIZE; } - gDynamicBasePower = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gMoveResultFlags = 0; - gCritMultiplier = 1; - bestDmg = 0; - bestMonId = 6; - // If we couldn't find the best mon in terms of typing, find the one that deals most damage. - for (i = 0; i < PARTY_SIZE; ++i) +} + +static bool32 AiExpectsToFaintPlayer(u32 battler) +{ + u8 target = gBattleStruct->aiChosenTarget[battler]; + + if (gBattleStruct->aiMoveOrAction[battler] > 3) + return FALSE; // AI not planning to use move + + if (GetBattlerSide(target) != GetBattlerSide(battler) + && CanIndexMoveFaintTarget(battler, target, gBattleStruct->aiMoveOrAction[battler], 0) + && AI_WhoStrikesFirst(battler, target, GetAIChosenMove(battler)) == AI_IS_FASTER) { - if (((u16)(GetMonData(&gEnemyParty[i], MON_DATA_SPECIES)) == SPECIES_NONE) - || (GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) - || (gBattlerPartyIndexes[battlerIn1] == i) - || (gBattlerPartyIndexes[battlerIn2] == i) - || (i == *(gBattleStruct->monToSwitchIntoId + battlerIn1)) - || (i == *(gBattleStruct->monToSwitchIntoId + battlerIn2))) - continue; - for (j = 0; j < MAX_MON_MOVES; ++j) - { - move = GetMonData(&gEnemyParty[i], MON_DATA_MOVE1 + j); - gBattleMoveDamage = 0; - if (move != MOVE_NONE && gMovesInfo[move].power != 1) - { - AI_CalcDmg(battler, opposingBattler); - TypeCalc(move, battler, opposingBattler); - } - if (bestDmg < gBattleMoveDamage) - { - bestDmg = gBattleMoveDamage; - bestMonId = i; - } - } + // We expect to faint the target and move first -> dont use an item + return TRUE; } - return bestMonId; + + return FALSE; } -static u8 GetAI_ItemType(u8 itemId, const u8 *itemEffect) // NOTE: should take u16 as item Id argument -{ - if (itemId == ITEM_FULL_RESTORE) - return AI_ITEM_FULL_RESTORE; - else if (itemEffect[4] & ITEM4_HEAL_HP) - return AI_ITEM_HEAL_HP; - else if (itemEffect[3] & ITEM3_STATUS_ALL) - return AI_ITEM_CURE_CONDITION; - else if ((itemEffect[0] & ITEM0_DIRE_HIT) || itemEffect[1] != 0 || itemEffect[2] != 0) - return AI_ITEM_X_STAT; - else if (itemEffect[3] & ITEM3_GUARD_SPEC) - return AI_ITEM_GUARD_SPECS; - else - return AI_ITEM_NOT_RECOGNIZABLE; -} - -static bool8 ShouldUseItem(u32 battler) +static bool32 ShouldUseItem(u32 battler) { + struct Pokemon *party; s32 i; u8 validMons = 0; - bool8 shouldUse = FALSE; + bool32 shouldUse = FALSE; - for (i = 0; i < PARTY_SIZE; ++i) - if (GetMonData(&gEnemyParty[i], MON_DATA_HP) != 0 - && GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE - && GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG) - ++validMons; - for (i = 0; i < MAX_TRAINER_ITEMS; ++i) + if (IsAiVsAiBattle()) + return FALSE; + + // If teaming up with player and Pokemon is on the right, or Pokemon is currently held by Sky Drop + if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT) + || gStatuses3[battler] & STATUS3_SKY_DROPPED) + return FALSE; + + if (gStatuses3[battler] & STATUS3_EMBARGO) + return FALSE; + + if (AiExpectsToFaintPlayer(battler)) + return FALSE; + + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = 0; i < PARTY_SIZE; i++) + { + if (IsValidForBattle(&party[i])) + { + validMons++; + } + } + + for (i = 0; i < MAX_TRAINER_ITEMS; i++) { u16 item; const u8 *itemEffects; - u8 paramOffset; u8 battlerSide; - if (i && validMons > (gBattleResources->battleHistory->itemsNo - i) + 1) - continue; item = gBattleResources->battleHistory->trainerItems[i]; if (item == ITEM_NONE) continue; @@ -574,99 +2057,97 @@ static bool8 ShouldUseItem(u32 battler) if (itemEffects == NULL) continue; - *(gBattleStruct->AI_itemType + battler / 2) = GetAI_ItemType(item, itemEffects); - switch (*(gBattleStruct->AI_itemType + battler / 2)) + switch (ItemId_GetBattleUsage(item)) { - case AI_ITEM_FULL_RESTORE: - if (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4) - break; - if (gBattleMons[battler].hp == 0) - break; - shouldUse = TRUE; + case EFFECT_ITEM_HEAL_AND_CURE_STATUS: + shouldUse = AI_ShouldHeal(battler, 0); break; - case AI_ITEM_HEAL_HP: - paramOffset = GetItemEffectParamOffset(battler, item, 4, 4); - if (paramOffset == 0 || gBattleMons[battler].hp == 0) - break; - if (gBattleMons[battler].hp < gBattleMons[battler].maxHP / 4 || gBattleMons[battler].maxHP - gBattleMons[battler].hp > itemEffects[paramOffset]) - shouldUse = TRUE; + case EFFECT_ITEM_RESTORE_HP: + shouldUse = AI_ShouldHeal(battler, itemEffects[GetItemEffectParamOffset(battler, item, 4, ITEM4_HEAL_HP)]); break; - case AI_ITEM_CURE_CONDITION: - *(gBattleStruct->AI_itemFlags + battler / 2) = 0; + case EFFECT_ITEM_CURE_STATUS: if (itemEffects[3] & ITEM3_SLEEP && gBattleMons[battler].status1 & STATUS1_SLEEP) - { - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x20; shouldUse = TRUE; - } - if (itemEffects[3] & ITEM3_POISON && (gBattleMons[battler].status1 & STATUS1_POISON || gBattleMons[battler].status1 & STATUS1_TOXIC_POISON)) - { - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x10; + if (itemEffects[3] & ITEM3_POISON && (gBattleMons[battler].status1 & STATUS1_POISON + || gBattleMons[battler].status1 & STATUS1_TOXIC_POISON)) shouldUse = TRUE; - } if (itemEffects[3] & ITEM3_BURN && gBattleMons[battler].status1 & STATUS1_BURN) - { - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x8; shouldUse = TRUE; - } - if (itemEffects[3] & ITEM3_FREEZE && gBattleMons[battler].status1 & STATUS1_FREEZE) - { - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x4; + if (itemEffects[3] & ITEM3_FREEZE && (gBattleMons[battler].status1 & STATUS1_FREEZE || gBattleMons[battler].status1 & STATUS1_FROSTBITE)) shouldUse = TRUE; - } if (itemEffects[3] & ITEM3_PARALYSIS && gBattleMons[battler].status1 & STATUS1_PARALYSIS) - { - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x2; shouldUse = TRUE; - } if (itemEffects[3] & ITEM3_CONFUSION && gBattleMons[battler].status2 & STATUS2_CONFUSION) - { - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x1; shouldUse = TRUE; - } break; - case AI_ITEM_X_STAT: - *(gBattleStruct->AI_itemFlags + battler / 2) = 0; - if (!gDisableStructs[battler].isFirstTurn) + case EFFECT_ITEM_INCREASE_STAT: + case EFFECT_ITEM_INCREASE_ALL_STATS: + if (!gDisableStructs[battler].isFirstTurn + || AI_OpponentCanFaintAiWithMod(battler, 0)) break; - switch (itemEffects[1]) { - case ITEM1_X_ATTACK: - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x1; - break; - case ITEM1_X_DEFENSE: - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x2; - break; - case ITEM1_X_SPEED: - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x4; - break; - case ITEM1_X_SPATK: - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x8; - break; - case ITEM1_X_ACCURACY: - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x20; - break; - case ITEM0_DIRE_HIT: - *(gBattleStruct->AI_itemFlags + battler / 2) |= 0x80; - break; - } shouldUse = TRUE; break; - case AI_ITEM_GUARD_SPECS: + case EFFECT_ITEM_SET_FOCUS_ENERGY: + if (!gDisableStructs[battler].isFirstTurn + || gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY + || AI_OpponentCanFaintAiWithMod(battler, 0)) + break; + shouldUse = TRUE; + break; + case EFFECT_ITEM_SET_MIST: battlerSide = GetBattlerSide(battler); if (gDisableStructs[battler].isFirstTurn && gSideTimers[battlerSide].mistTimer == 0) shouldUse = TRUE; break; - case AI_ITEM_NOT_RECOGNIZABLE: + case EFFECT_ITEM_REVIVE: + gBattleStruct->itemPartyIndex[battler] = GetFirstFaintedPartyIndex(battler); + if (gBattleStruct->itemPartyIndex[battler] != PARTY_SIZE) // Revive if possible. + shouldUse = TRUE; + break; + default: return FALSE; } if (shouldUse) { + // Set selected party ID to current battler if none chosen. if (gBattleStruct->itemPartyIndex[battler] == PARTY_SIZE) gBattleStruct->itemPartyIndex[battler] = gBattlerPartyIndexes[battler]; - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_USE_ITEM, 0); - *(gBattleStruct->chosenItem + (battler / 2) * 2) = item; + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_USE_ITEM, 0); + gBattleStruct->chosenItem[battler] = item; gBattleResources->battleHistory->trainerItems[i] = 0; return shouldUse; } } + + return FALSE; +} + +static bool32 AI_ShouldHeal(u32 battler, u32 healAmount) +{ + bool32 shouldHeal = FALSE; + + if (gBattleMons[battler].hp < gBattleMons[battler].maxHP / 4 + || gBattleMons[battler].hp == 0 + || (healAmount != 0 && gBattleMons[battler].maxHP - gBattleMons[battler].hp > healAmount)) + { + // We have low enough HP to consider healing + shouldHeal = !AI_OpponentCanFaintAiWithMod(battler, healAmount); // if target can kill us even after we heal, why bother + } + + return shouldHeal; +} + +static bool32 AI_OpponentCanFaintAiWithMod(u32 battler, u32 healAmount) +{ + u32 i; + // Check special cases to NOT heal + for (i = 0; i < gBattlersCount; i++) + { + if (GetBattlerSide(i) == B_SIDE_PLAYER && CanTargetFaintAiWithMod(i, battler, healAmount, 0)) + { + // Target is expected to faint us + return TRUE; + } + } return FALSE; } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c new file mode 100644 index 000000000..8b6a9f6f6 --- /dev/null +++ b/src/battle_ai_util.c @@ -0,0 +1,3724 @@ +#include "global.h" +// #include "battle_z_move.h" +#include "malloc.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_ai_util.h" +#include "battle_ai_main.h" +#include "battle_ai_switch_items.h" +#include "battle_setup.h" +#include "event_data.h" +#include "data.h" +#include "item.h" +#include "pokemon.h" +#include "random.h" +#include "util.h" +#include "constants/abilities.h" +#include "constants/battle_ai.h" +#include "constants/battle_move_effects.h" +#include "constants/hold_effects.h" +#include "constants/moves.h" +#include "constants/items.h" + +#define CHECK_MOVE_FLAG(flag) \ + s32 i; \ + u16 *moves = GetMovesArray(battler); \ + for (i = 0; i < MAX_MON_MOVES; i++) \ + { \ + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && gMovesInfo[moves[i]].flag) \ + return TRUE; \ + } \ + return FALSE + +static u32 AI_GetEffectiveness(uq4_12_t multiplier); + +// Functions +u32 GetAIChosenMove(u32 battlerId) +{ + return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]); +} + +bool32 AI_RandLessThan(u32 val) +{ + if ((Random() % 0xFF) < val) + return TRUE; + return FALSE; +} + +bool32 IsAiVsAiBattle(void) +{ + return (B_FLAG_AI_VS_AI_BATTLE && FlagGet(B_FLAG_AI_VS_AI_BATTLE)); +} + +bool32 BattlerHasAi(u32 battlerId) +{ + switch (GetBattlerPosition(battlerId)) + { + case B_POSITION_PLAYER_LEFT: + if (IsAiVsAiBattle()) + return TRUE; + default: + return FALSE; + case B_POSITION_OPPONENT_LEFT: + return TRUE; + case B_POSITION_PLAYER_RIGHT: + if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) || IsAiVsAiBattle()) + return TRUE; + else + return FALSE; + case B_POSITION_OPPONENT_RIGHT: + return TRUE; + } +} + +bool32 IsAiBattlerAware(u32 battlerId) +{ + if (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT + || AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT) + return TRUE; + + return BattlerHasAi(battlerId); +} + +void ClearBattlerMoveHistory(u32 battlerId) +{ + memset(BATTLE_HISTORY->usedMoves[battlerId], 0, sizeof(BATTLE_HISTORY->usedMoves[battlerId])); + memset(BATTLE_HISTORY->moveHistory[battlerId], 0, sizeof(BATTLE_HISTORY->moveHistory[battlerId])); + BATTLE_HISTORY->moveHistoryIndex[battlerId] = 0; +} + +void RecordLastUsedMoveBy(u32 battlerId, u32 move) +{ + u8 *index = &BATTLE_HISTORY->moveHistoryIndex[battlerId]; + + if (++(*index) >= AI_MOVE_HISTORY_COUNT) + *index = 0; + BATTLE_HISTORY->moveHistory[battlerId][*index] = move; +} + +void RecordKnownMove(u32 battlerId, u32 move) +{ + s32 i; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (BATTLE_HISTORY->usedMoves[battlerId][i] == move) + break; + if (BATTLE_HISTORY->usedMoves[battlerId][i] == MOVE_NONE) + { + BATTLE_HISTORY->usedMoves[battlerId][i] = move; + AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].moves[i] = move; + break; + } + } +} + +void RecordAllMoves(u32 battler) +{ + memcpy(AI_PARTY->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]].moves, gBattleMons[battler].moves, MAX_MON_MOVES * sizeof(u16)); +} + +void RecordAbilityBattle(u32 battlerId, u32 abilityId) +{ + BATTLE_HISTORY->abilities[battlerId] = abilityId; + AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability = abilityId; +} + +void ClearBattlerAbilityHistory(u32 battlerId) +{ + BATTLE_HISTORY->abilities[battlerId] = ABILITY_NONE; +} + +void RecordItemEffectBattle(u32 battlerId, u32 itemEffect) +{ + BATTLE_HISTORY->itemEffects[battlerId] = itemEffect; + AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect = itemEffect; +} + +void ClearBattlerItemEffectHistory(u32 battlerId) +{ + BATTLE_HISTORY->itemEffects[battlerId] = 0; +} + +void SaveBattlerData(u32 battlerId) +{ + if (!BattlerHasAi(battlerId)) + { + u32 i; + + AI_THINKING_STRUCT->saved[battlerId].ability = gBattleMons[battlerId].ability; + AI_THINKING_STRUCT->saved[battlerId].heldItem = gBattleMons[battlerId].item; + AI_THINKING_STRUCT->saved[battlerId].species = gBattleMons[battlerId].species; + for (i = 0; i < 4; i++) + AI_THINKING_STRUCT->saved[battlerId].moves[i] = gBattleMons[battlerId].moves[i]; + } + // Save and restore types even for AI controlled battlers in case it gets changed during move evaluation process. + AI_THINKING_STRUCT->saved[battlerId].types[0] = gBattleMons[battlerId].type1; + AI_THINKING_STRUCT->saved[battlerId].types[1] = gBattleMons[battlerId].type2; +} + +static bool32 ShouldFailForIllusion(u32 illusionSpecies, u32 battlerId) +{ + u32 i, j; + const struct LevelUpMove *learnset; + + if (BATTLE_HISTORY->abilities[battlerId] == ABILITY_ILLUSION) + return FALSE; + + // Don't fall for Illusion if the mon used a move it cannot know. + for (i = 0; i < MAX_MON_MOVES; i++) + { + u32 move = BATTLE_HISTORY->usedMoves[battlerId][i]; + if (move == MOVE_NONE) + continue; + + learnset = GetSpeciesLevelUpLearnset(illusionSpecies); + for (j = 0; learnset[j].move != MOVE_UNAVAILABLE; j++) + { + if (learnset[j].move == move) + break; + } + // The used move is in the learnsets of the fake species. + if (learnset[j].move != MOVE_UNAVAILABLE) + continue; + + // The used move can be learned from Tm/Hm or Move Tutors. + if (CanLearnTeachableMove(illusionSpecies, move)) + continue; + + // 'Illegal move', AI won't fail for the illusion. + return FALSE; + } + + return TRUE; +} + +void SetBattlerData(u32 battlerId) +{ + if (!BattlerHasAi(battlerId)) + { + u32 i, species, illusionSpecies, side; + side = GetBattlerSide(battlerId); + + // Simulate Illusion + species = gBattleMons[battlerId].species; + illusionSpecies = GetIllusionMonSpecies(battlerId); + if (illusionSpecies != SPECIES_NONE && ShouldFailForIllusion(illusionSpecies, battlerId)) + { + // If the battler's type has not been changed, AI assumes the types of the illusion mon. + if (gBattleMons[battlerId].type1 == gSpeciesInfo[species].types[0] + && gBattleMons[battlerId].type2 == gSpeciesInfo[species].types[1]) + { + gBattleMons[battlerId].type1 = gSpeciesInfo[illusionSpecies].types[0]; + gBattleMons[battlerId].type2 = gSpeciesInfo[illusionSpecies].types[1]; + } + species = illusionSpecies; + } + + // Use the known battler's ability. + if (AI_PARTY->mons[side][gBattlerPartyIndexes[battlerId]].ability != ABILITY_NONE) + gBattleMons[battlerId].ability = AI_PARTY->mons[side][gBattlerPartyIndexes[battlerId]].ability; + // Check if mon can only have one ability. + else if (gSpeciesInfo[species].abilities[1] == ABILITY_NONE + || gSpeciesInfo[species].abilities[1] == gSpeciesInfo[species].abilities[0]) + gBattleMons[battlerId].ability = gSpeciesInfo[species].abilities[0]; + // The ability is unknown. + else + gBattleMons[battlerId].ability = ABILITY_NONE; + + if (AI_PARTY->mons[side][gBattlerPartyIndexes[battlerId]].heldEffect == 0) + gBattleMons[battlerId].item = 0; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (AI_PARTY->mons[side][gBattlerPartyIndexes[battlerId]].moves[i] == 0) + gBattleMons[battlerId].moves[i] = 0; + } + } +} + +void RestoreBattlerData(u32 battlerId) +{ + if (!BattlerHasAi(battlerId)) + { + u32 i; + + gBattleMons[battlerId].ability = AI_THINKING_STRUCT->saved[battlerId].ability; + gBattleMons[battlerId].item = AI_THINKING_STRUCT->saved[battlerId].heldItem; + gBattleMons[battlerId].species = AI_THINKING_STRUCT->saved[battlerId].species; + for (i = 0; i < 4; i++) + gBattleMons[battlerId].moves[i] = AI_THINKING_STRUCT->saved[battlerId].moves[i]; + } + gBattleMons[battlerId].type1 = AI_THINKING_STRUCT->saved[battlerId].types[0]; + gBattleMons[battlerId].type2 = AI_THINKING_STRUCT->saved[battlerId].types[1]; +} + +u32 GetHealthPercentage(u32 battlerId) +{ + return (u32)((100 * gBattleMons[battlerId].hp) / gBattleMons[battlerId].maxHP); +} + +bool32 AtMaxHp(u32 battlerId) +{ + if (AI_DATA->hpPercents[battlerId] == 100) + return TRUE; + return FALSE; +} + +bool32 IsBattlerTrapped(u32 battler, bool32 checkSwitch) +{ + u32 holdEffect = AI_DATA->holdEffects[battler]; + + if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) + return FALSE; + if (checkSwitch && holdEffect == HOLD_EFFECT_SHED_SHELL) + return FALSE; + else if (!checkSwitch && GetBattlerAbility(battler) == ABILITY_RUN_AWAY) + return FALSE; + else if (!checkSwitch && holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) + return FALSE; + else if (gBattleMons[battler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED)) + return TRUE; + else if (gStatuses3[battler] & (STATUS3_ROOTED | STATUS3_SKY_DROPPED)) + return TRUE; + else if (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK) + return TRUE; + else if (IsAbilityPreventingEscape(battler)) + return TRUE; + + return FALSE; +} + +u32 GetTotalBaseStat(u32 species) +{ + return gSpeciesInfo[species].baseHP + + gSpeciesInfo[species].baseAttack + + gSpeciesInfo[species].baseDefense + + gSpeciesInfo[species].baseSpeed + + gSpeciesInfo[species].baseSpAttack + + gSpeciesInfo[species].baseSpDefense; +} + +bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) +{ + int i; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i]; + if (gMovesInfo[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE) + return TRUE; + if (gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAI, opposingBattler, GetAIChosenMove(battlerAI)) == AI_IS_SLOWER) + return TRUE; + } + return FALSE; +} + +// move checks +bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect) +{ + if (ability == ABILITY_OVERCOAT + || (B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) + || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES) + return FALSE; + return TRUE; +} + +// This function checks if all physical/special moves are either unusable or unreasonable to use. +// Consider a pokemon boosting their attack against a ghost pokemon having only normal-type physical attacks. +bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category) +{ + s32 i, moveType; + u32 usable = 0; + u32 unusable = AI_DATA->moveLimitations[attacker]; + u16 *moves = GetMovesArray(attacker); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE + && moves[i] != MOVE_UNAVAILABLE + && GetBattleMoveCategory(moves[i]) == category + && !(unusable & gBitTable[i])) + { + SetTypeBeforeUsingMove(moves[i], attacker); + GET_MOVE_TYPE(moves[i], moveType); + if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, AI_DATA->abilities[target], FALSE) != 0) + usable |= gBitTable[i]; + } + } + + return (usable == 0); +} + +// To save computation time this function has 2 variants. One saves, sets and restores battlers, while the other doesn't. +s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower) +{ + SaveBattlerData(battlerAtk); + SaveBattlerData(battlerDef); + return AI_CalcDamage(move, battlerAtk, battlerDef, typeEffectiveness, considerZPower, AI_GetWeather(AI_DATA)); +} + +static inline s32 LowestRollDmg(s32 dmg) +{ + dmg *= 100 - 15; + dmg /= 100; + return dmg; +} + +bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef) +{ + s32 moveType; + struct AiLogicData *aiData = AI_DATA; + u32 battlerDefAbility; + + if (DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move)) + battlerDefAbility = ABILITY_NONE; + else + battlerDefAbility = aiData->abilities[battlerDef]; + + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + + switch (battlerDefAbility) + { + case ABILITY_VOLT_ABSORB: + case ABILITY_MOTOR_DRIVE: + case ABILITY_LIGHTNING_ROD: + if (moveType == TYPE_ELECTRIC) + return TRUE; + break; + case ABILITY_WATER_ABSORB: + case ABILITY_DRY_SKIN: + case ABILITY_STORM_DRAIN: + if (moveType == TYPE_WATER) + return TRUE; + break; + case ABILITY_FLASH_FIRE: + if (moveType == TYPE_FIRE) + return TRUE; + break; + case ABILITY_SOUNDPROOF: + if (gMovesInfo[move].soundMove) + return TRUE; + break; + case ABILITY_BULLETPROOF: + if (gMovesInfo[move].ballisticMove) + return TRUE; + break; + case ABILITY_SAP_SIPPER: + if (moveType == TYPE_GRASS) + return TRUE; + break; + case ABILITY_EARTH_EATER: + if (moveType == TYPE_GROUND) + return TRUE; + break; + } + + switch (gMovesInfo[move].effect) + { + case EFFECT_DREAM_EATER: + if (!AI_IsBattlerAsleepOrComatose(battlerDef)) + return TRUE; + break; + case EFFECT_BELCH: + if (ItemId_GetPocket(GetUsedHeldItem(battlerAtk)) != POCKET_BERRY_POUCH) + return TRUE; + break; + case EFFECT_LAST_RESORT: + if (!CanUseLastResort(battlerAtk)) + return TRUE; + break; + case EFFECT_LOW_KICK: + if (IsDynamaxed(battlerDef)) + return TRUE; + break; + case EFFECT_FAIL_IF_NOT_ARG_TYPE: + if (!IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[move].argument)) + return TRUE; + break; + case EFFECT_HIT_SET_REMOVE_TERRAIN: + if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)) + return TRUE; + break; + } + + return FALSE; +} + +s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower, u32 weather) +{ + s32 dmg, moveType; + uq4_12_t effectivenessMultiplier; + bool32 isDamageMoveUnusable = FALSE; + struct AiLogicData *aiData = AI_DATA; + + SetBattlerData(battlerAtk); + SetBattlerData(battlerDef); + + // TODO: Z-moves + /* if (considerZPower && IsViableZMove(battlerAtk, move)) + { + //temporarily enable z moves for damage calcs + gBattleStruct->zmove.baseMoves[battlerAtk] = move; + gBattleStruct->zmove.active = TRUE; + } + else */if (gMovesInfo[move].effect == EFFECT_PHOTON_GEYSER) + gBattleStruct->swapDamageCategory = (GetCategoryBasedOnStats(gBattlerAttacker) == DAMAGE_CATEGORY_PHYSICAL); + + if (gMovesInfo[move].effect == EFFECT_NATURE_POWER) + move = GetNaturePowerMove(); + + gBattleStruct->dynamicMoveType = 0; + + + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + + if (gMovesInfo[move].power) + isDamageMoveUnusable = IsDamageMoveUnusable(move, battlerAtk, battlerDef); + + effectivenessMultiplier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, aiData->abilities[battlerDef], FALSE); + if (gMovesInfo[move].power && !isDamageMoveUnusable) + { + s32 critChanceIndex, normalDmg, fixedBasePower, n; + + ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, moveType); + // Certain moves like Rollout calculate damage based on values which change during the move execution, but before calling dmg calc. + switch (gMovesInfo[move].effect) + { + case EFFECT_ROLLOUT: + n = gDisableStructs[battlerAtk].rolloutTimer - 1; + fixedBasePower = CalcRolloutBasePower(battlerAtk, gMovesInfo[move].power, n < 0 ? 5 : n); + break; + case EFFECT_FURY_CUTTER: + fixedBasePower = CalcFuryCutterBasePower(gMovesInfo[move].power, min(gDisableStructs[battlerAtk].furyCutterCounter + 1, 5)); + break; + default: + fixedBasePower = 0; + break; + } + normalDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower, + effectivenessMultiplier, weather, FALSE, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + + critChanceIndex = CalcCritChanceStageArgs(battlerAtk, battlerDef, move, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk]); + if (critChanceIndex > 1) // Consider crit damage only if a move has at least +1 crit chance + { + s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower, + effectivenessMultiplier, weather, TRUE, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + u32 critChance = GetCritHitChance(critChanceIndex); + // With critChance getting closer to 1, dmg gets closer to critDmg. + dmg = LowestRollDmg((critDmg + normalDmg * (critChance - 1)) / (critChance)); + } + else + { + dmg = LowestRollDmg(normalDmg); + } + + if (!gBattleStruct->zmove.active) + { + // Handle dynamic move damage + switch (gMovesInfo[move].effect) + { + case EFFECT_LEVEL_DAMAGE: + case EFFECT_PSYWAVE: + dmg = gBattleMons[battlerAtk].level * (aiData->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); + break; + case EFFECT_FIXED_DAMAGE_ARG: + dmg = gMovesInfo[move].argument * (aiData->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); + break; + case EFFECT_MULTI_HIT: + dmg *= (aiData->abilities[battlerAtk] == ABILITY_SKILL_LINK + && !(move == MOVE_WATER_SHURIKEN && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_ASH) + ? 5 : 3); + break; + case EFFECT_ENDEAVOR: + // If target has less HP than user, Endeavor does no damage + dmg = max(0, gBattleMons[battlerDef].hp - gBattleMons[battlerAtk].hp); + break; + case EFFECT_SUPER_FANG: + dmg = (aiData->abilities[battlerAtk] == ABILITY_PARENTAL_BOND + ? max(2, gBattleMons[battlerDef].hp * 3 / 4) + : max(1, gBattleMons[battlerDef].hp / 2)); + break; + case EFFECT_FINAL_GAMBIT: + dmg = gBattleMons[battlerAtk].hp; + break; + case EFFECT_BEAT_UP: + if (B_BEAT_UP >= GEN_5) + { + u32 partyCount = CalculatePartyCount(GetBattlerParty(battlerAtk)); + u32 i; + gBattleStruct->beatUpSlot = 0; + dmg = 0; + for (i = 0; i < partyCount; i++) + { + dmg += CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, FALSE, FALSE, FALSE); + } + gBattleStruct->beatUpSlot = 0; + } + break; + } + + // Handle other multi-strike moves + if (gMovesInfo[move].strikeCount > 1 && gMovesInfo[move].effect != EFFECT_TRIPLE_KICK) + dmg *= gMovesInfo[move].strikeCount; + + if (dmg == 0) + dmg = 1; + } + } + else + { + dmg = 0; + } + + RestoreBattlerData(battlerAtk); + RestoreBattlerData(battlerDef); + + // convert multiper to AI_EFFECTIVENESS_xX + *typeEffectiveness = AI_GetEffectiveness(effectivenessMultiplier); + + gBattleStruct->swapDamageCategory = FALSE; + gBattleStruct->zmove.active = FALSE; + gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE; + + return dmg; +} + +bool32 AI_IsDamagedByRecoil(u32 battler) +{ + u32 ability = AI_DATA->abilities[battler]; + if (ability == ABILITY_MAGIC_GUARD || ability == ABILITY_ROCK_HEAD) + return FALSE; + return TRUE; +} + +// Decide whether move having an additional effect for . +static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s32 noOfHitsToKo) +{ + u32 i; + u32 abilityDef = AI_DATA->abilities[battlerDef]; + u32 abilityAtk = AI_DATA->abilities[battlerAtk]; + + switch (gMovesInfo[move].effect) + { + case EFFECT_HIT_ESCAPE: + if (CountUsablePartyMons(battlerAtk) != 0 && ShouldPivot(battlerAtk, battlerDef, abilityDef, move, AI_THINKING_STRUCT->movesetIndex)) + return TRUE; + break; + case EFFECT_FELL_STINGER: + if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK)) + return TRUE; + break; + } + + // check ADDITIONAL_EFFECTS + for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + { + // Consider move effects that target self + if (gMovesInfo[move].additionalEffects[i].self) + { + switch (gMovesInfo[move].additionalEffects[i].moveEffect) + { + case MOVE_EFFECT_ATK_PLUS_1: + if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK)) + return TRUE; + break; + case MOVE_EFFECT_DEF_PLUS_2: + case MOVE_EFFECT_DEF_PLUS_1: + if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_DEF)) + return TRUE; + break; + case MOVE_EFFECT_SPD_PLUS_1: + if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_SPEED)) + return TRUE; + break; + case MOVE_EFFECT_SP_ATK_PLUS_1: + if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_SPATK)) + return TRUE; + break; + case MOVE_EFFECT_ALL_STATS_UP: + for (i = STAT_ATK; i <= NUM_STATS; i++) + { + if (BattlerStatCanRise(battlerAtk, abilityAtk, i)) + return TRUE; + } + break; + } + } + else // consider move effects that hinder the target + { + switch (gMovesInfo[move].additionalEffects[i].moveEffect) + { + case MOVE_EFFECT_POISON: + case MOVE_EFFECT_TOXIC: + if (AI_CanPoison(battlerAtk, battlerDef, abilityDef, move, MOVE_NONE)) + return TRUE; + break; + case MOVE_EFFECT_BURN: + if (AI_CanBurn(battlerAtk, battlerDef, abilityDef, BATTLE_PARTNER(battlerAtk), move, MOVE_NONE)) + return TRUE; + break; + case MOVE_EFFECT_FREEZE_OR_FROSTBITE: + if (AI_CanGetFrostbite(battlerDef, abilityDef)) + return TRUE; + break; + case MOVE_EFFECT_PARALYSIS: + if (AI_CanParalyze(battlerAtk, battlerDef, abilityDef, move, MOVE_NONE)) + return TRUE; + break; + case MOVE_EFFECT_CONFUSION: + if (AI_CanConfuse(battlerAtk, battlerDef, abilityDef, BATTLE_PARTNER(battlerAtk), move, MOVE_NONE)) + return TRUE; + break; + case MOVE_EFFECT_FLINCH: + if (ShouldTryToFlinch(battlerAtk, battlerDef, abilityAtk, abilityDef, move)) + return TRUE; + break; + case MOVE_EFFECT_ATK_MINUS_1: + case MOVE_EFFECT_DEF_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SP_ATK_MINUS_1: + case MOVE_EFFECT_SP_DEF_MINUS_1: + case MOVE_EFFECT_ACC_MINUS_1: + case MOVE_EFFECT_EVS_MINUS_1: + if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1) + return TRUE; + break; + case MOVE_EFFECT_ATK_MINUS_2: + case MOVE_EFFECT_DEF_MINUS_2: + case MOVE_EFFECT_SPD_MINUS_2: + case MOVE_EFFECT_SP_ATK_MINUS_2: + case MOVE_EFFECT_SP_DEF_MINUS_2: + case MOVE_EFFECT_ACC_MINUS_2: + case MOVE_EFFECT_EVS_MINUS_2: + if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1) + return TRUE; + break; + } + } + } + + return FALSE; +} + +static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s32 noOfHitsToKo) +{ + u32 abilityAtk = AI_DATA->abilities[battlerAtk]; + u32 abilityDef = AI_DATA->abilities[battlerDef]; + u8 i; + + // recoil + if (gMovesInfo[move].recoil > 0 && AI_IsDamagedByRecoil(battlerAtk)) + return TRUE; + + switch (gMovesInfo[move].effect) + { + case EFFECT_MIND_BLOWN: + case EFFECT_MAX_HP_50_RECOIL: + return TRUE; + case EFFECT_RECOIL_IF_MISS: + if (AI_IsDamagedByRecoil(battlerAtk)) + return TRUE; + break; + default: + { + for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + { + switch (gMovesInfo[move].additionalEffects[i].moveEffect) + { + case MOVE_EFFECT_ATK_MINUS_1: + case MOVE_EFFECT_DEF_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SP_ATK_MINUS_1: + case MOVE_EFFECT_SP_ATK_TWO_DOWN: + case MOVE_EFFECT_V_CREATE: + case MOVE_EFFECT_ATK_DEF_DOWN: + case MOVE_EFFECT_DEF_SPDEF_DOWN: + case MOVE_EFFECT_SP_DEF_MINUS_1: + case MOVE_EFFECT_SP_DEF_MINUS_2: + if ((gMovesInfo[move].additionalEffects[i].self && GetBattlerAbility(battlerAtk) != ABILITY_CONTRARY) + || (noOfHitsToKo != 1 && abilityDef == ABILITY_CONTRARY && !IsMoldBreakerTypeAbility(abilityAtk))) + return TRUE; + break; + case MOVE_EFFECT_RECHARGE: + return gMovesInfo[move].additionalEffects[i].self; + } + } + break; + } + } + return FALSE; +} + +// Checks if one of the moves has side effects or perks, assuming equal dmg or equal no of hits to KO +s32 AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo) +{ + bool32 effect1, effect2; + s32 defAbility = AI_DATA->abilities[battlerDef]; + + // Check if physical moves hurt. + if (AI_DATA->holdEffects[battlerAtk] != HOLD_EFFECT_PROTECTIVE_PADS + && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_ROCKY_HELMET + || defAbility == ABILITY_IRON_BARBS || defAbility == ABILITY_ROUGH_SKIN)) + { + if (IS_MOVE_PHYSICAL(move1) && !IS_MOVE_PHYSICAL(move2)) + return 1; + if (IS_MOVE_PHYSICAL(move2) && !IS_MOVE_PHYSICAL(move1)) + return 0; + } + + // Check additional effects. + effect1 = AI_IsMoveEffectInMinus(battlerAtk, battlerDef, move1, noOfHitsToKo); + effect2 = AI_IsMoveEffectInMinus(battlerAtk, battlerDef, move2, noOfHitsToKo); + if (effect2 && !effect1) + return 1; + if (effect1 && !effect2) + return -1; + + effect1 = AI_IsMoveEffectInPlus(battlerAtk, battlerDef, move1, noOfHitsToKo); + effect2 = AI_IsMoveEffectInPlus(battlerAtk, battlerDef, move2, noOfHitsToKo); + if (effect2 && !effect1) + return -1; + if (effect1 && !effect2) + return 1; + + return 0; +} + +u32 GetNoOfHitsToKO(u32 dmg, s32 hp) +{ + if (dmg == 0) + return 0; + return hp / (dmg + 1) + 1; +} + +u32 GetNoOfHitsToKOBattlerDmg(u32 dmg, u32 battlerDef) +{ + return GetNoOfHitsToKO(dmg, gBattleMons[battlerDef].hp); +} + +u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex) +{ + return GetNoOfHitsToKOBattlerDmg(AI_DATA->simulatedDmg[battlerAtk][battlerDef][moveIndex], battlerDef); +} + +u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef) +{ + int bestDmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + + return (bestDmg * 100) / gBattleMons[battlerDef].maxHP; +} + +uq4_12_t AI_GetTypeEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) +{ + uq4_12_t typeEffectiveness; + u32 moveType; + + SaveBattlerData(battlerAtk); + SaveBattlerData(battlerDef); + + SetBattlerData(battlerAtk); + SetBattlerData(battlerDef); + + gBattleStruct->dynamicMoveType = 0; + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], FALSE); + + RestoreBattlerData(battlerAtk); + RestoreBattlerData(battlerDef); + + return typeEffectiveness; +} + +u32 AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) +{ + gMoveResultFlags = 0; + return AI_GetEffectiveness(AI_GetTypeEffectiveness(move, battlerAtk, battlerDef)); +} + +static u32 AI_GetEffectiveness(uq4_12_t multiplier) +{ + switch (multiplier) + { + case UQ_4_12(0.0): + return AI_EFFECTIVENESS_x0; + case UQ_4_12(0.125): + return AI_EFFECTIVENESS_x0_125; + case UQ_4_12(0.25): + return AI_EFFECTIVENESS_x0_25; + case UQ_4_12(0.5): + return AI_EFFECTIVENESS_x0_5; + case UQ_4_12(1.0): + default: + return AI_EFFECTIVENESS_x1; + case UQ_4_12(2.0): + return AI_EFFECTIVENESS_x2; + case UQ_4_12(4.0): + return AI_EFFECTIVENESS_x4; + case UQ_4_12(8.0): + return AI_EFFECTIVENESS_x8; + } +} + +/* Checks to see if AI will move ahead of another battler + * Output: + * AI_IS_FASTER: is user(ai) faster + * AI_IS_SLOWER: is target faster +*/ +s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered) +{ + u32 fasterAI = 0, fasterPlayer = 0, i; + s8 prioAI = 0; + s8 prioBattler2 = 0; + u16 *battler2Moves = GetMovesArray(battler2); + + // Check move priorities first. + prioAI = GetMovePriority(battlerAI, moveConsidered); + for (i = 0; i < MAX_MON_MOVES; i++) + { + prioBattler2 = GetMovePriority(battler2, battler2Moves[i]); + if (battler2Moves[i] == MOVE_NONE || battler2Moves[i] == MOVE_UNAVAILABLE + || (prioBattler2 > prioAI && !CanIndexMoveFaintTarget(battler2, battlerAI, i , 2))) + continue; + + if (prioAI > prioBattler2) + fasterAI++; + else if (prioBattler2 > prioAI) + fasterPlayer++; + } + + if (fasterAI > fasterPlayer) + { + return AI_IS_FASTER; + } + else if (fasterAI < fasterPlayer) + { + return AI_IS_SLOWER; + } + else + { + if (prioAI > prioBattler2) + return AI_IS_FASTER; // if we didn't know any of battler 2's moves to compare priorities, assume they don't have a prio+ move + // Priorities are the same(at least comparing to moves the AI is aware of), decide by speed. + if (GetWhichBattlerFasterArgs(battlerAI, battler2, TRUE, + AI_DATA->abilities[battlerAI], AI_DATA->abilities[battler2], + AI_DATA->holdEffects[battlerAI], AI_DATA->holdEffects[battler2], + AI_DATA->speedStats[battlerAI], AI_DATA->speedStats[battler2], + prioAI, prioBattler2) == 1) + return AI_IS_FASTER; + else + return AI_IS_SLOWER; + } +} + +// Check if target has means to faint ai mon. +bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk) +{ + s32 i; + u32 unusable = AI_DATA->moveLimitations[battlerDef]; + u16 *moves = GetMovesArray(battlerDef); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & gBitTable[i]) + && AI_DATA->simulatedDmg[battlerDef][battlerAtk][i] >= gBattleMons[battlerAtk].hp) + { + return TRUE; + } + } + + return FALSE; +} + +u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk) +{ + u32 i; + u32 currNumberOfHits; + u32 leastNumberOfHits = UNKNOWN_NO_OF_HITS; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + currNumberOfHits = GetNoOfHitsToKOBattler(battlerDef, battlerAtk, i); + if (currNumberOfHits != 0) + { + if (currNumberOfHits < leastNumberOfHits) + leastNumberOfHits = currNumberOfHits; + } + } + return leastNumberOfHits; +} + +u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef) +{ + u32 i; + u32 move = 0; + u32 bestDmg = 0; + u32 unusable = AI_DATA->moveLimitations[battlerAtk]; + u16 *moves = GetMovesArray(battlerAtk); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & gBitTable[i]) + && bestDmg < AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]) + { + bestDmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]; + move = moves[i]; + } + } + return move; +} + +// Check if AI mon has the means to faint the target with any of its moves. +// If numHits > 1, check if the target will be KO'ed by that number of hits (ignoring healing effects) +bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits) +{ + s32 i, dmg; + u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; + u16 *moves = gBattleMons[battlerAtk].moves; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(moveLimitations & gBitTable[i])) + { + // Use the pre-calculated value in simulatedDmg instead of re-calculating it + dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]; + + if (numHits) + dmg *= numHits; + + if (gBattleMons[battlerDef].hp <= dmg) + return TRUE; + } + } + + return FALSE; +} + +bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits) +{ + u32 indexSlot = GetMoveSlot(GetMovesArray(battlerDef), move); + if (indexSlot < MAX_MON_MOVES) + { + if (GetNoOfHitsToKO(AI_DATA->simulatedDmg[battlerDef][battlerAtk][indexSlot], gBattleMons[battlerAtk].hp) <= nHits) + return TRUE; + } + return FALSE; +} + +// Check if target has means to faint ai mon after modding hp/dmg +bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod) +{ + u32 i; + u32 unusable = AI_DATA->moveLimitations[battlerDef]; + s32 dmg; + u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; + u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod; + + if (hpCheck > gBattleMons[battlerAtk].maxHP) + hpCheck = gBattleMons[battlerAtk].maxHP; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]; + if (dmgMod) + dmg *= dmgMod; + + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & gBitTable[i]) && dmg >= hpCheck) + { + return TRUE; + } + } + + return FALSE; +} + +bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability) +{ + if (IsBattlerAlive(battlerId) && AI_DATA->abilities[battlerId] == ability) + return TRUE; + else if (IsBattlerAlive(BATTLE_PARTNER(battlerId)) && AI_DATA->abilities[BATTLE_PARTNER(battlerId)] == ability) + return TRUE; + else + return FALSE; +} + +// does NOT include ability suppression checks +s32 AI_DecideKnownAbilityForTurn(u32 battlerId) +{ + u32 knownAbility = GetBattlerAbility(battlerId); + + // We've had ability overwritten by e.g. Worry Seed. It is not part of AI_PARTY in case of switching + if (gBattleStruct->overwrittenAbilities[battlerId]) + return gBattleStruct->overwrittenAbilities[battlerId]; + + // The AI knows its own ability. + if (IsAiBattlerAware(battlerId)) + return knownAbility; + + // Check neutralizing gas, gastro acid + if (knownAbility == ABILITY_NONE) + return knownAbility; + + if (AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability != ABILITY_NONE) + return AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability; + + // Abilities that prevent fleeing - treat as always known + if (knownAbility == ABILITY_SHADOW_TAG || knownAbility == ABILITY_MAGNET_PULL || knownAbility == ABILITY_ARENA_TRAP) + return knownAbility; + + // Else, guess the ability + if (gSpeciesInfo[gBattleMons[battlerId].species].abilities[0] != ABILITY_NONE) + { + u32 abilityGuess = ABILITY_NONE; + while (abilityGuess == ABILITY_NONE) + { + abilityGuess = gSpeciesInfo[gBattleMons[battlerId].species].abilities[Random() % NUM_ABILITY_SLOTS]; + } + + return abilityGuess; + } + + return ABILITY_NONE; // Unknown. +} + +u32 AI_DecideHoldEffectForTurn(u32 battlerId) +{ + u32 holdEffect; + + if (!IsAiBattlerAware(battlerId)) + holdEffect = AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect; + else + holdEffect = GetBattlerHoldEffect(battlerId, FALSE); + + if (AI_THINKING_STRUCT->aiFlags[battlerId] & AI_FLAG_NEGATE_UNAWARE) + return holdEffect; + + if (gStatuses3[battlerId] & STATUS3_EMBARGO) + return HOLD_EFFECT_NONE; + if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) + return HOLD_EFFECT_NONE; + if (AI_DATA->abilities[battlerId] == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) + return HOLD_EFFECT_NONE; + + return holdEffect; +} + +bool32 AI_IsTerrainAffected(u32 battlerId, u32 flags) +{ + if (gStatuses3[battlerId] & STATUS3_SEMI_INVULNERABLE) + return FALSE; + else if (!(gFieldStatuses & flags)) + return FALSE; + return AI_IsBattlerGrounded(battlerId); +} + +// different from IsBattlerGrounded in that we don't always know battler's hold effect or ability +bool32 AI_IsBattlerGrounded(u32 battlerId) +{ + u32 holdEffect = AI_DATA->holdEffects[battlerId]; + + if (holdEffect == HOLD_EFFECT_IRON_BALL) + return TRUE; + else if (gFieldStatuses & STATUS_FIELD_GRAVITY) + return TRUE; + else if (gStatuses3[battlerId] & STATUS3_ROOTED) + return TRUE; + else if (gStatuses3[battlerId] & STATUS3_SMACKED_DOWN) + return TRUE; + else if (gStatuses3[battlerId] & STATUS3_TELEKINESIS) + return FALSE; + else if (gStatuses3[battlerId] & STATUS3_MAGNET_RISE) + return FALSE; + else if (holdEffect == HOLD_EFFECT_AIR_BALLOON) + return FALSE; + else if (AI_DATA->abilities[battlerId] == ABILITY_LEVITATE) + return FALSE; + else if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING)) + return FALSE; + else + return TRUE; +} + +bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move) +{ + if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE) + return FALSE; // AI handicap flag: doesn't understand ability suppression concept + + if (IsMoldBreakerTypeAbility(atkAbility) || gMovesInfo[move].ignoresTargetAbility) + return TRUE; + + return FALSE; +} + +static inline bool32 AI_WeatherHasEffect(struct AiLogicData *aiData) +{ + if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE) + return TRUE; // AI doesn't understand weather supression (handicap) + + return aiData->weatherHasEffect; // weather damping abilities are announced +} + +u32 AI_GetWeather(struct AiLogicData *aiData) +{ + if (gBattleWeather == B_WEATHER_NONE) + return B_WEATHER_NONE; + if (!AI_WeatherHasEffect(aiData)) + return B_WEATHER_NONE; + return gBattleWeather; +} + +u32 AI_GetBattlerMoveTargetType(u32 battlerId, u32 move) +{ + if (gMovesInfo[move].effect == EFFECT_EXPANDING_FORCE && AI_IsTerrainAffected(battlerId, STATUS_FIELD_PSYCHIC_TERRAIN)) + return MOVE_TARGET_BOTH; + else + return gMovesInfo[move].target; +} + +bool32 IsAromaVeilProtectedMove(u32 move) +{ + switch (move) + { + case MOVE_DISABLE: + case MOVE_ATTRACT: + case MOVE_ENCORE: + case MOVE_TORMENT: + case MOVE_TAUNT: + case MOVE_HEAL_BLOCK: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect) +{ + switch (moveEffect) + { + case EFFECT_SLEEP: + case EFFECT_TOXIC: + case EFFECT_POISON: + case EFFECT_PARALYZE: + case EFFECT_WILL_O_WISP: + case EFFECT_YAWN: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsConfusionMoveEffect(u32 moveEffect) +{ + switch (moveEffect) + { + case EFFECT_CONFUSE: + case EFFECT_SWAGGER: + case EFFECT_FLATTER: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsHazardMoveEffect(u32 moveEffect) +{ + switch (moveEffect) + { + case EFFECT_SPIKES: + case EFFECT_TOXIC_SPIKES: + case EFFECT_STICKY_WEB: + case EFFECT_STEALTH_ROCK: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility) +{ + if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE) + return FALSE; + + if (move == MOVE_SKY_DROP + || move == MOVE_SNIPE_SHOT + || atkAbility == ABILITY_PROPELLER_TAIL + || atkAbility == ABILITY_STALWART) + return TRUE; + return FALSE; +} + +bool32 IsSemiInvulnerable(u32 battlerDef, u32 move) +{ + if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) + return TRUE; + else if (!gMovesInfo[move].damagesAirborne && gStatuses3[battlerDef] & STATUS3_ON_AIR) + return TRUE; + else if (!gMovesInfo[move].damagesUnderwater && gStatuses3[battlerDef] & STATUS3_UNDERWATER) + return TRUE; + else if (!gMovesInfo[move].damagesUnderground && gStatuses3[battlerDef] & STATUS3_UNDERGROUND) + return TRUE; + else + return FALSE; +} + +bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move) +{ + u32 weather; + if (IsSemiInvulnerable(battlerDef, move)) + return FALSE; + + //TODO - anticipate protect move? + + // always hits + if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS || gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk) + return TRUE; + + if (AI_DATA->abilities[battlerDef] == ABILITY_NO_GUARD || AI_DATA->abilities[battlerAtk] == ABILITY_NO_GUARD) + return TRUE; + + if (B_TOXIC_NEVER_MISS >= GEN_6 && gMovesInfo[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON)) + return TRUE; + + // discouraged from hitting + weather = AI_GetWeather(AI_DATA); + if ((weather & B_WEATHER_SUN) && gMovesInfo[move].effect == EFFECT_THUNDER) + return FALSE; + + // increased accuracy but don't always hit + if ((weather & B_WEATHER_RAIN) && gMovesInfo[move].effect == EFFECT_THUNDER) + return TRUE; + if ((weather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && gMovesInfo[move].effect == EFFECT_BLIZZARD) + return TRUE; + if (B_MINIMIZE_DMG_ACC >= GEN_6 && (gStatuses3[battlerDef] & STATUS3_MINIMIZED) && gMovesInfo[move].minimizeDoubleDamage) + return TRUE; + if (gMovesInfo[move].accuracy == 0) + return TRUE; + + return FALSE; +} + +bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move) +{ + u32 holdEffect = AI_DATA->holdEffects[battlerDef]; + u32 accuracy = AI_DATA->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + + gPotentialItemEffectBattler = battlerDef; + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < AI_DATA->holdEffectParams[battlerDef]) + return FALSE; //probabilistically speaking, focus band should activate so dont OHKO + else if (holdEffect == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef)) + return FALSE; + + if (!DoesBattlerIgnoreAbilityChecks(atkAbility, move) && defAbility == ABILITY_STURDY) + return FALSE; + + if ((((gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS) + && gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk) + || atkAbility == ABILITY_NO_GUARD || defAbility == ABILITY_NO_GUARD) + && gBattleMons[battlerAtk].level >= gBattleMons[battlerDef].level) + { + return TRUE; + } + else // test the odds + { + u32 odds = accuracy + (gBattleMons[battlerAtk].level - gBattleMons[battlerDef].level); + if (B_SHEER_COLD_ACC >= GEN_7 && move == MOVE_SHEER_COLD && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE)) + odds -= 10; + if (Random() % 100 + 1 < odds && gBattleMons[battlerAtk].level >= gBattleMons[battlerDef].level) + return TRUE; + } + return FALSE; +} + +bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect) +{ + u32 weather = AI_GetWeather(AI_DATA); + if (weather & B_WEATHER_SANDSTORM) + return FALSE; + + if (ability == ABILITY_SAND_VEIL + || ability == ABILITY_SAND_RUSH + || ability == ABILITY_SAND_FORCE + || ability == ABILITY_OVERCOAT + || ability == ABILITY_MAGIC_GUARD + || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES + || IS_BATTLER_OF_TYPE(battler, TYPE_ROCK) + || IS_BATTLER_OF_TYPE(battler, TYPE_STEEL) + || IS_BATTLER_OF_TYPE(battler, TYPE_GROUND) + || HasMoveEffect(battler, EFFECT_SHORE_UP) + || HasMoveEffect(battler, EFFECT_WEATHER_BALL)) + { + return TRUE; + } + return FALSE; +} + +bool32 ShouldSetHail(u32 battler, u32 ability, u32 holdEffect) +{ + u32 weather = AI_GetWeather(AI_DATA); + if (weather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) + return FALSE; + + if (ability == ABILITY_SNOW_CLOAK + || ability == ABILITY_ICE_BODY + || ability == ABILITY_FORECAST + || ability == ABILITY_SLUSH_RUSH + || ability == ABILITY_MAGIC_GUARD + || ability == ABILITY_OVERCOAT + || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES + || IS_BATTLER_OF_TYPE(battler, TYPE_ICE) + || HasMoveEffect(battler, EFFECT_BLIZZARD) + || HasMoveEffect(battler, EFFECT_AURORA_VEIL) + || HasMoveEffect(battler, EFFECT_WEATHER_BALL)) + { + return TRUE; + } + return FALSE; +} + +bool32 ShouldSetRain(u32 battlerAtk, u32 atkAbility, u32 holdEffect) +{ + u32 weather = AI_GetWeather(AI_DATA); + if (weather & B_WEATHER_RAIN) + return FALSE; + + if (holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA + && (atkAbility == ABILITY_SWIFT_SWIM + || atkAbility == ABILITY_FORECAST + || atkAbility == ABILITY_HYDRATION + || atkAbility == ABILITY_RAIN_DISH + || atkAbility == ABILITY_DRY_SKIN + || HasMoveEffect(battlerAtk, EFFECT_THUNDER) + || HasMoveEffect(battlerAtk, EFFECT_WEATHER_BALL) + || HasMoveWithType(battlerAtk, TYPE_WATER))) + { + return TRUE; + } + return FALSE; +} + +bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, u32 holdEffect) +{ + u32 weather = AI_GetWeather(AI_DATA); + if (weather & B_WEATHER_SUN) + return FALSE; + + if (holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA + && (atkAbility == ABILITY_CHLOROPHYLL + || atkAbility == ABILITY_FLOWER_GIFT + || atkAbility == ABILITY_FORECAST + || atkAbility == ABILITY_LEAF_GUARD + || atkAbility == ABILITY_SOLAR_POWER + || atkAbility == ABILITY_HARVEST + || HasMoveEffect(battlerAtk, EFFECT_SOLAR_BEAM) + || HasMoveEffect(battlerAtk, EFFECT_MORNING_SUN) + || HasMoveEffect(battlerAtk, EFFECT_SYNTHESIS) + || HasMoveEffect(battlerAtk, EFFECT_MOONLIGHT) + || HasMoveEffect(battlerAtk, EFFECT_WEATHER_BALL) + || HasMoveEffect(battlerAtk, EFFECT_GROWTH) + || HasMoveWithType(battlerAtk, TYPE_FIRE))) + { + return TRUE; + } + return FALSE; +} + +bool32 ShouldSetSnow(u32 battler, u32 ability, u32 holdEffect) +{ + u32 weather = AI_GetWeather(AI_DATA); + if (weather & (B_WEATHER_SNOW | B_WEATHER_HAIL)) + return FALSE; + + if (ability == ABILITY_SNOW_CLOAK + || ability == ABILITY_ICE_BODY + || ability == ABILITY_FORECAST + || ability == ABILITY_SLUSH_RUSH + || IS_BATTLER_OF_TYPE(battler, TYPE_ICE) + || HasMoveEffect(battler, EFFECT_BLIZZARD) + || HasMoveEffect(battler, EFFECT_AURORA_VEIL) + || HasMoveEffect(battler, EFFECT_WEATHER_BALL)) + { + return TRUE; + } + return FALSE; +} + +void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove, s32 *score) +{ + // TODO more sophisticated logic + u32 uses = gDisableStructs[battlerAtk].protectUses; + + /*if (GetMoveResultFlags(predictedMove) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) + { + ADJUST_SCORE_PTR(-5); + return; + }*/ + + if (uses == 0) + { + if (predictedMove != MOVE_NONE && predictedMove != 0xFFFF && !IS_MOVE_STATUS(predictedMove)) + ADJUST_SCORE_PTR(DECENT_EFFECT); + else if (Random() % 256 < 100) + ADJUST_SCORE_PTR(WEAK_EFFECT); + } + else + { + if (IsDoubleBattle()) + ADJUST_SCORE_PTR(-(2 * min(uses, 3))); + else + ADJUST_SCORE_PTR(-(min(uses, 3))); + } + + if (gBattleMons[battlerAtk].status1 & (STATUS1_PSN_ANY | STATUS1_BURN | STATUS1_FROSTBITE) + || gBattleMons[battlerAtk].status2 & (STATUS2_CURSED | STATUS2_INFATUATION) + || gStatuses3[battlerAtk] & (STATUS3_PERISH_SONG | STATUS3_LEECHSEED | STATUS3_YAWN)) + { + ADJUST_SCORE_PTR(-1); + } + + if (gBattleMons[battlerDef].status1 & STATUS1_TOXIC_POISON + || gBattleMons[battlerDef].status2 & (STATUS2_CURSED | STATUS2_INFATUATION) + || gStatuses3[battlerDef] & (STATUS3_PERISH_SONG | STATUS3_LEECHSEED | STATUS3_YAWN)) + ADJUST_SCORE_PTR(DECENT_EFFECT); +} + +// stat stages +bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat) +{ + if (gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) + { + if (AI_DATA->holdEffects[battler] == HOLD_EFFECT_CLEAR_AMULET + || battlerAbility == ABILITY_CLEAR_BODY + || battlerAbility == ABILITY_WHITE_SMOKE + || battlerAbility == ABILITY_FULL_METAL_BODY) + return FALSE; + + switch (stat) + { + case STAT_ATK: + return !(battlerAbility == ABILITY_HYPER_CUTTER); + case STAT_DEF: + return !(battlerAbility == ABILITY_BIG_PECKS); + case STAT_SPEED: + // If AI is faster and doesn't have any mons left, lowering speed doesn't give any + return !(AI_WhoStrikesFirst(sBattler_AI, battler, AI_THINKING_STRUCT->moveConsidered) == AI_IS_FASTER + && CountUsablePartyMons(sBattler_AI) == 0 + && !HasMoveEffect(sBattler_AI, EFFECT_ELECTRO_BALL)); + case STAT_ACC: + return !(battlerAbility == ABILITY_KEEN_EYE || (B_ILLUMINATE_EFFECT >= GEN_9 && battlerAbility == ABILITY_ILLUMINATE)); + } + return TRUE; + } + + return FALSE; +} + +bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat) +{ + if ((gBattleMons[battler].statStages[stat] < MAX_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) + || (battlerAbility == ABILITY_CONTRARY && gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE)) + return TRUE; + return FALSE; +} + +bool32 AreBattlersStatsMaxed(u32 battlerId) +{ + u32 i; + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerId].statStages[i] < MAX_STAT_STAGE) + return FALSE; + } + return TRUE; +} + +bool32 AnyStatIsRaised(u32 battlerId) +{ + u32 i; + + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerId].statStages[i] > DEFAULT_STAT_STAGE) + return TRUE; + } + return FALSE; +} + +u32 CountPositiveStatStages(u32 battlerId) +{ + u32 count = 0; + u32 i; + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerId].statStages[i] > DEFAULT_STAT_STAGE) + count++; + } + return count; +} + +u32 CountNegativeStatStages(u32 battlerId) +{ + u32 count = 0; + u32 i; + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerId].statStages[i] < DEFAULT_STAT_STAGE) + count++; + } + return count; +} + +bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility) +{ + if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) + && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4 + && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + && defAbility != ABILITY_WHITE_SMOKE + && defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_HYPER_CUTTER + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility) +{ + if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) + && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 + && HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + && defAbility != ABILITY_WHITE_SMOKE + && defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_BIG_PECKS + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility) +{ + if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) + && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (!AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + && defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_WHITE_SMOKE + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility) +{ + if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) + && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4 + && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + && defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_WHITE_SMOKE + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility) +{ + if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) + && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4 + && HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + && defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_WHITE_SMOKE + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility) +{ + if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) + && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + && defAbility != ABILITY_WHITE_SMOKE + && defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_KEEN_EYE + && defAbility != ABILITY_MINDS_EYE + && (B_ILLUMINATE_EFFECT >= GEN_9 && defAbility != ABILITY_ILLUMINATE) + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility) +{ + if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) + && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + && defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_WHITE_SMOKE + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + return TRUE; + return FALSE; +} + +bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, u32 numHits) +{ + s32 dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][index]; + + if (numHits) + dmg *= numHits; + + if (gBattleMons[battlerDef].hp <= dmg) + return TRUE; + return FALSE; +} + +u16 *GetMovesArray(u32 battler) +{ + if (IsAiBattlerAware(battler) || IsAiBattlerAware(BATTLE_PARTNER(battler))) + return gBattleMons[battler].moves; + else + return gBattleResources->battleHistory->usedMoves[battler]; +} + +bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensive) +{ + u32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (onlyOffensive && IS_MOVE_STATUS(moves[i])) + continue; + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetBattleMoveCategory(moves[i]) != category) + return FALSE; + } + + return TRUE; +} + +bool32 HasMoveWithCategory(u32 battler, u32 category) +{ + u32 i; + u16 *moves = GetMovesArray(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetBattleMoveCategory(moves[i]) == category) + return TRUE; + } + return FALSE; +} + +bool32 HasMoveWithType(u32 battler, u32 type) +{ + s32 i; + u16 *moves = GetMovesArray(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && gMovesInfo[moves[i]].type == type) + return TRUE; + } + + return FALSE; +} + +bool32 HasMoveEffect(u32 battlerId, u32 effect) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE + && gMovesInfo[moves[i]].effect == effect) + return TRUE; + } + + return FALSE; +} + +bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE + && gMovesInfo[moves[i]].effect == effect + && (gMovesInfo[moves[i]].argument & argument)) + return TRUE; + } + + return FALSE; +} + +bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE + && MoveHasAdditionalEffect(moves[i], moveEffect)) + return TRUE; + } + + return FALSE; +} + +bool32 HasMoveWithCriticalHitChance(u32 battlerId) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE + && gMovesInfo[moves[i]].criticalHitStage > 0) + return TRUE; + } + + return FALSE; +} + +bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE + && gMovesInfo[moves[i]].effect != exception + && MoveHasAdditionalEffect(moves[i], moveEffect)) + return TRUE; + } + + return FALSE; +} + +bool32 HasMove(u32 battlerId, u32 move) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && moves[i] == move) + return TRUE; + } + + return FALSE; +} + +bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect) +{ + s32 i; + u16 *moves = GetMovesArray(battlerAtk); + u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] == MOVE_NONE || moves[i] == MOVE_UNAVAILABLE) + continue; + + if (!(gBitTable[i] & moveLimitations)) + { + if (ignoreStatus && IS_MOVE_STATUS(moves[i])) + continue; + else if ((!IS_MOVE_STATUS(moves[i]) && gMovesInfo[moves[i]].accuracy == 0) + || AI_GetBattlerMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) + continue; + + if (AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] <= accCheck) + return TRUE; + } + } + + return FALSE; +} + +bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef) +{ + u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; + u32 i; + u16 *moves = GetMovesArray(battlerAtk); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] == MOVE_NONE) + break; + if (!(gBitTable[i] & moveLimitations)) + { + if (gMovesInfo[moves[i]].effect == EFFECT_SLEEP + && AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] < 85) + return TRUE; + } + } + return FALSE; +} + +bool32 IsHealingMove(u32 move) +{ + return gMovesInfo[move].healingMove; +} + +bool32 HasHealingEffect(u32 battlerId) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && IsHealingMove(moves[i])) + return TRUE; + } + + return FALSE; +} + +bool32 IsTrappingMove(u32 move) +{ + switch (gMovesInfo[move].effect) + { + case EFFECT_MEAN_LOOK: + case EFFECT_FAIRY_LOCK: + //case EFFECT_NO_RETREAT: // TODO + return TRUE; + default: + return MoveHasAdditionalEffect(move, MOVE_EFFECT_PREVENT_ESCAPE) + || MoveHasAdditionalEffect(move, MOVE_EFFECT_WRAP); + } +} + +bool32 HasTrappingMoveEffect(u32 battler) +{ + s32 i; + u16 *moves = GetMovesArray(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && IsTrappingMove(moves[i])) + return TRUE; + } + + return FALSE; +} + +bool32 HasThawingMove(u32 battler) +{ + CHECK_MOVE_FLAG(thawsUser); +} + +bool32 IsUngroundingEffect(u32 effect) +{ + switch (effect) + { + case EFFECT_MAGNET_RISE: + return TRUE; + default: + return FALSE; + } +} + +// for anger point +bool32 IsAttackBoostMoveEffect(u32 effect) +{ + switch (effect) + { + case EFFECT_ATTACK_UP: + case EFFECT_ATTACK_UP_2: + case EFFECT_ATTACK_ACCURACY_UP: + case EFFECT_ATTACK_SPATK_UP: + case EFFECT_DRAGON_DANCE: + case EFFECT_COIL: + case EFFECT_BELLY_DRUM: + case EFFECT_BULK_UP: + case EFFECT_GROWTH: + case EFFECT_FILLET_AWAY: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsStatRaisingEffect(u32 effect) +{ + switch (effect) + { + case EFFECT_ATTACK_UP: + case EFFECT_ATTACK_UP_2: + case EFFECT_DEFENSE_UP: + case EFFECT_DEFENSE_UP_2: + case EFFECT_DEFENSE_UP_3: + case EFFECT_SPEED_UP: + case EFFECT_SPEED_UP_2: + case EFFECT_SPECIAL_ATTACK_UP: + case EFFECT_SPECIAL_ATTACK_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_3: + case EFFECT_SPECIAL_DEFENSE_UP: + case EFFECT_SPECIAL_DEFENSE_UP_2: + case EFFECT_ACCURACY_UP: + case EFFECT_ACCURACY_UP_2: + case EFFECT_EVASION_UP: + case EFFECT_EVASION_UP_2: + case EFFECT_MINIMIZE: + case EFFECT_DEFENSE_CURL: + case EFFECT_CALM_MIND: + case EFFECT_COSMIC_POWER: + case EFFECT_DRAGON_DANCE: + case EFFECT_ACUPRESSURE: + case EFFECT_SHELL_SMASH: + case EFFECT_SHIFT_GEAR: + case EFFECT_ATTACK_ACCURACY_UP: + case EFFECT_ATTACK_SPATK_UP: + case EFFECT_GROWTH: + case EFFECT_COIL: + case EFFECT_QUIVER_DANCE: + case EFFECT_BULK_UP: + case EFFECT_GEOMANCY: + case EFFECT_STOCKPILE: + case EFFECT_VICTORY_DANCE: + return TRUE; + case EFFECT_CHARGE: + return B_CHARGE_SPDEF_RAISE >= GEN_5; + default: + return FALSE; + } +} + +bool32 IsStatLoweringEffect(u32 effect) +{ + // ignore other potentially-beneficial effects like defog, gravity + switch (effect) + { + case EFFECT_ATTACK_DOWN: + case EFFECT_DEFENSE_DOWN: + case EFFECT_SPEED_DOWN: + case EFFECT_SPECIAL_ATTACK_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_ACCURACY_DOWN: + case EFFECT_EVASION_DOWN: + case EFFECT_ATTACK_DOWN_2: + case EFFECT_DEFENSE_DOWN_2: + case EFFECT_SPEED_DOWN_2: + case EFFECT_SPECIAL_ATTACK_DOWN_2: + case EFFECT_SPECIAL_DEFENSE_DOWN_2: + case EFFECT_ACCURACY_DOWN_2: + case EFFECT_EVASION_DOWN_2: + case EFFECT_TICKLE: + case EFFECT_CAPTIVATE: + case EFFECT_NOBLE_ROAR: + case EFFECT_MEMENTO: + return TRUE; + default: + return FALSE; + } +} + +bool32 HasDamagingMove(u32 battlerId) +{ + u32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && gMovesInfo[moves[i]].power != 0) + return TRUE; + } + + return FALSE; +} + +bool32 HasDamagingMoveOfType(u32 battlerId, u32 type) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE + && gMovesInfo[moves[i]].type == type && gMovesInfo[moves[i]].power != 0) + return TRUE; + } + + return FALSE; +} + +bool32 HasSubstituteIgnoringMove(u32 battler) +{ + CHECK_MOVE_FLAG(ignoresSubstitute); +} + +bool32 HasHighCritRatioMove(u32 battler) +{ + s32 i; + u16 *moves = GetMovesArray(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && gMovesInfo[moves[i]].criticalHitStage > 0) + return TRUE; + } + + return FALSE; +} + +bool32 HasMagicCoatAffectedMove(u32 battler) +{ + CHECK_MOVE_FLAG(magicCoatAffected); +} + +bool32 HasSnatchAffectedMove(u32 battler) +{ + CHECK_MOVE_FLAG(snatchAffected); +} + +bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move) +{ + switch (gMovesInfo[move].effect) + { + case EFFECT_SOLAR_BEAM: + case EFFECT_TWO_TURNS_ATTACK: + return !(AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB + || (AI_GetWeather(AI_DATA) & gMovesInfo[move].argument)); + default: + return FALSE; + } +} + +static u32 GetLeechSeedDamage(u32 battlerId) +{ + u32 damage = 0; + if ((gStatuses3[battlerId] & STATUS3_LEECHSEED) + && gBattleMons[gStatuses3[battlerId] & STATUS3_LEECHSEED_BATTLER].hp != 0) + { + damage = GetNonDynamaxMaxHP(battlerId) / 8; + if (damage == 0) + damage = 1; + } + return damage; +} + +static u32 GetNightmareDamage(u32 battlerId) +{ + u32 damage = 0; + if ((gBattleMons[battlerId].status2 & STATUS2_NIGHTMARE) && gBattleMons[battlerId].status1 & STATUS1_SLEEP) + { + damage = GetNonDynamaxMaxHP(battlerId) / 4; + if (damage == 0) + damage = 1; + } + return damage; +} + +static u32 GetCurseDamage(u32 battlerId) +{ + u32 damage = 0; + if (gBattleMons[battlerId].status2 & STATUS2_CURSED) + { + damage = GetNonDynamaxMaxHP(battlerId) / 4; + if (damage == 0) + damage = 1; + } + return damage; +} + +static u32 GetTrapDamage(u32 battlerId) +{ + // ai has no knowledge about turns remaining + u32 damage = 0; + u32 holdEffect = AI_DATA->holdEffects[gBattleStruct->wrappedBy[battlerId]]; + if (gBattleMons[battlerId].status2 & STATUS2_WRAPPED) + { + if (holdEffect == HOLD_EFFECT_BINDING_BAND) + damage = GetNonDynamaxMaxHP(battlerId) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); + else + damage = GetNonDynamaxMaxHP(battlerId) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); + + if (damage == 0) + damage = 1; + } + return damage; +} + +static u32 GetPoisonDamage(u32 battlerId) +{ + u32 damage = 0; + + if (AI_DATA->abilities[battlerId] == ABILITY_POISON_HEAL) + return damage; + + if (gBattleMons[battlerId].status1 & STATUS1_POISON) + { + damage = gBattleMons[battlerId].maxHP / 8; + if (damage == 0) + damage = 1; + } + else if (gBattleMons[battlerId].status1 & STATUS1_TOXIC_POISON) + { + damage = gBattleMons[battlerId].maxHP / 16; + if (damage == 0) + damage = 1; + if ((gBattleMons[battlerId].status1 & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_TURN(15)) // not 16 turns + gBattleMons[battlerId].status1 += STATUS1_TOXIC_TURN(1); + damage *= (gBattleMons[battlerId].status1 & STATUS1_TOXIC_COUNTER) >> 8; + } + return damage; +} + +static bool32 BattlerAffectedBySandstorm(u32 battlerId, u32 ability) +{ + if (!IS_BATTLER_OF_TYPE(battlerId, TYPE_ROCK) + && !IS_BATTLER_OF_TYPE(battlerId, TYPE_GROUND) + && !IS_BATTLER_OF_TYPE(battlerId, TYPE_STEEL) + && ability != ABILITY_SAND_VEIL + && ability != ABILITY_SAND_FORCE + && ability != ABILITY_SAND_RUSH + && ability != ABILITY_OVERCOAT) + return TRUE; + return FALSE; +} + +static bool32 BattlerAffectedByHail(u32 battlerId, u32 ability) +{ + if (!IS_BATTLER_OF_TYPE(battlerId, TYPE_ICE) + && ability != ABILITY_SNOW_CLOAK + && ability != ABILITY_OVERCOAT + && ability != ABILITY_ICE_BODY) + return TRUE; + return FALSE; +} + +static u32 GetWeatherDamage(u32 battlerId) +{ + u32 ability = AI_DATA->abilities[battlerId]; + u32 holdEffect = AI_DATA->holdEffects[battlerId]; + u32 damage = 0; + u32 weather = AI_GetWeather(AI_DATA); + if (!weather) + return 0; + + if (weather & B_WEATHER_SANDSTORM) + { + if (BattlerAffectedBySandstorm(battlerId, ability) + && !(gStatuses3[battlerId] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + && holdEffect != HOLD_EFFECT_SAFETY_GOGGLES) + { + damage = GetNonDynamaxMaxHP(battlerId) / 16; + if (damage == 0) + damage = 1; + } + } + if ((weather & B_WEATHER_HAIL) && ability != ABILITY_ICE_BODY) + { + if (BattlerAffectedByHail(battlerId, ability) + && !(gStatuses3[battlerId] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + && holdEffect != HOLD_EFFECT_SAFETY_GOGGLES) + { + damage = GetNonDynamaxMaxHP(battlerId) / 16; + if (damage == 0) + damage = 1; + } + } + return damage; +} + +u32 GetBattlerSecondaryDamage(u32 battlerId) +{ + u32 secondaryDamage; + + if (AI_DATA->abilities[battlerId] == ABILITY_MAGIC_GUARD) + return FALSE; + + secondaryDamage = GetLeechSeedDamage(battlerId) + + GetNightmareDamage(battlerId) + + GetCurseDamage(battlerId) + + GetTrapDamage(battlerId) + + GetPoisonDamage(battlerId) + + GetWeatherDamage(battlerId); + + return secondaryDamage; +} + +bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability) +{ + if ((BattlerAffectedBySandstorm(battler, ability) || BattlerAffectedByHail(battler, ability)) + && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 16) + return TRUE; + + return FALSE; +} + +bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability) +{ + if (GetBattlerSecondaryDamage(battler) != 0 + && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 16) + return TRUE; + return FALSE; +} + +static bool32 AnyUsefulStatIsRaised(u32 battler) +{ + u32 statId; + + for (statId = STAT_ATK; statId < NUM_BATTLE_STATS; statId++) + { + if (gBattleMons[battler].statStages[statId] > DEFAULT_STAT_STAGE) + { + switch (statId) + { + case STAT_ATK: + if (HasMoveWithCategory(battler, DAMAGE_CATEGORY_PHYSICAL)) + return TRUE; + break; + case STAT_SPATK: + if (HasMoveWithCategory(battler, DAMAGE_CATEGORY_SPECIAL)) + return TRUE; + break; + case STAT_SPEED: + return TRUE; + } + } + } + + return FALSE; +} + +struct Pokemon *GetPartyBattlerPartyData(u32 battlerId, u32 switchBattler) +{ + struct Pokemon *mon; + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) + mon = &gPlayerParty[switchBattler]; + else + mon = &gEnemyParty[switchBattler]; + return mon; +} + +static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler) +{ + struct Pokemon *mon = GetPartyBattlerPartyData(currBattler, switchBattler); + u32 ability = GetMonAbility(mon); // we know our own party data + u32 holdEffect; + u32 species = GetMonData(mon, MON_DATA_SPECIES); + u32 flags = gSideStatuses[GetBattlerSide(currBattler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES); + s32 hazardDamage = 0; + u32 type1 = gSpeciesInfo[species].types[0]; + u32 type2 = gSpeciesInfo[species].types[1]; + u32 maxHp = GetMonData(mon, MON_DATA_MAX_HP); + + if (flags == 0) + return FALSE; + + if (ability == ABILITY_MAGIC_GUARD) + return FALSE; + if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || ability == ABILITY_KLUTZ) + holdEffect = HOLD_EFFECT_NONE; + else + holdEffect = gItems[GetMonData(mon, MON_DATA_HELD_ITEM)].holdEffect; + if (holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS) + return FALSE; + + if (flags & SIDE_STATUS_STEALTH_ROCK) + hazardDamage += GetStealthHazardDamageByTypesAndHP(gMovesInfo[MOVE_STEALTH_ROCK].type, type1, type2, maxHp); + + if (flags & SIDE_STATUS_SPIKES && ((type1 != TYPE_FLYING && type2 != TYPE_FLYING + && ability != ABILITY_LEVITATE && holdEffect != HOLD_EFFECT_AIR_BALLOON) + || holdEffect == HOLD_EFFECT_IRON_BALL || gFieldStatuses & STATUS_FIELD_GRAVITY)) + { + s32 spikesDmg = maxHp / ((5 - gSideTimers[GetBattlerSide(currBattler)].spikesAmount) * 2); + if (spikesDmg == 0) + spikesDmg = 1; + hazardDamage += spikesDmg; + } + + if (hazardDamage >= GetMonData(mon, MON_DATA_HP)) + return TRUE; + return FALSE; +} + +enum { + DONT_PIVOT, + CAN_TRY_PIVOT, + PIVOT, +}; +bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex) +{ + bool32 hasStatBoost = AnyUsefulStatIsRaised(battlerAtk) || gBattleMons[battlerDef].statStages[STAT_EVASION] >= 9; //Significant boost in evasion for any class + bool32 shouldSwitch; + u32 battlerToSwitch; + + shouldSwitch = ShouldSwitch(battlerAtk, FALSE); + battlerToSwitch = gBattleStruct->AI_monToSwitchIntoId[battlerAtk]; + + if (PartyBattlerShouldAvoidHazards(battlerAtk, battlerToSwitch)) + return DONT_PIVOT; + + if (!IsDoubleBattle()) + { + if (CountUsablePartyMons(battlerAtk) == 0) + return CAN_TRY_PIVOT; // can't switch, but attack might still be useful + + //TODO - predict opponent switching + /*if (IsPredictedToSwitch(battlerDef, battlerAtk) && !hasStatBoost) + return PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/ + + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first + { + if (!CanAIFaintTarget(battlerAtk, battlerDef, 0)) // Can't KO foe otherwise + { + if (CanAIFaintTarget(battlerAtk, battlerDef, 2)) + { + // attacker can kill target in two hits (theoretically) + if (CanTargetFaintAi(battlerDef, battlerAtk)) + return PIVOT; // Won't get the two turns, pivot + + if (!IS_MOVE_STATUS(move) && (shouldSwitch + || (AtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH + || (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY) + || defAbility == ABILITY_MULTISCALE + || defAbility == ABILITY_SHADOW_SHIELD)))) + return PIVOT; // pivot to break sash/sturdy/multiscale + } + else if (!hasStatBoost) + { + if (!IS_MOVE_STATUS(move) && (AtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH + || (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY) + || defAbility == ABILITY_MULTISCALE + || defAbility == ABILITY_SHADOW_SHIELD))) + return PIVOT; // pivot to break sash/sturdy/multiscale + + if (shouldSwitch) + return PIVOT; + + /* TODO - check if switchable mon unafffected by/will remove hazards + if (gSideStatuses[battlerAtk] & SIDE_STATUS_SPIKES && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS) + return PIVOT;*/ + + /*if (BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]) && switchScore >= SWITCHING_INCREASE_WALLS_FOE) + return PIVOT;*/ + + /*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE) + { + bool32 physMoveInMoveset = PhysicalMoveInMoveset(battlerAtk); + bool32 specMoveInMoveset = SpecialMoveInMoveset(battlerAtk); + + //Pivot if attacking stats are bad + if (physMoveInMoveset && !specMoveInMoveset) + { + if (STAT_STAGE_ATK < 6) + return PIVOT; + } + else if (!physMoveInMoveset && specMoveInMoveset) + { + if (STAT_STAGE_SPATK < 6) + return PIVOT; + } + else if (physMoveInMoveset && specMoveInMoveset) + { + if (STAT_STAGE_ATK < 6 && STAT_STAGE_SPATK < 6) + return PIVOT; + } + + return CAN_TRY_PIVOT; + }*/ + } + } + } + else // Opponent Goes First + { + if (CanTargetFaintAi(battlerDef, battlerAtk)) + { + if (gMovesInfo[move].effect == EFFECT_TELEPORT) + return DONT_PIVOT; // If you're going to faint because you'll go second, use a different move + else + return CAN_TRY_PIVOT; // You're probably going to faint anyways so if for some reason you don't, better switch + } + else if (CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 2)) // Foe can 2HKO AI + { + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + { + if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk])) + return CAN_TRY_PIVOT; // Use this move to KO if you must + } + else // Can't KO the foe + { + return PIVOT; + } + } + else // Foe can 3HKO+ AI + { + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + { + if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]) // This is the only move that can KO + && !hasStatBoost) //You're not wasting a valuable stat boost + { + return CAN_TRY_PIVOT; + } + } + else if (CanAIFaintTarget(battlerAtk, battlerDef, 2)) + { + // can knock out foe in 2 hits + if (IS_MOVE_STATUS(move) && (shouldSwitch //Damaging move + //&& (switchScore >= SWITCHING_INCREASE_RESIST_ALL_MOVES + SWITCHING_INCREASE_KO_FOE //remove hazards + || (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef)))) + return DONT_PIVOT; // Pivot to break the sash + else + return CAN_TRY_PIVOT; + } + else + { + //if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_KO_FOE) + //return PIVOT; //Only switch if way better matchup + + if (!hasStatBoost) + { + // TODO - check if switching prevents/removes hazards + //if (gSideStatuses[battlerAtk] & SIDE_STATUS_SPIKES && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS) + //return PIVOT; + + // TODO - not always a good idea + //if (BattlerWillFaintFromSecondaryDamage(battlerAtk) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE) + //return PIVOT; + + /*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE) + { + bool32 physMoveInMoveset = PhysicalMoveInMoveset(battlerAtk); + bool32 specMoveInMoveset = SpecialMoveInMoveset(battlerAtk); + + //Pivot if attacking stats are bad + if (physMoveInMoveset && !specMoveInMoveset) + { + if (STAT_STAGE_ATK < 6) + return PIVOT; + } + else if (!physMoveInMoveset && specMoveInMoveset) + { + if (STAT_STAGE_SPATK < 6) + return PIVOT; + } + else if (physMoveInMoveset && specMoveInMoveset) + { + if (STAT_STAGE_ATK < 6 && STAT_STAGE_SPATK < 6) + return PIVOT; + } + }*/ + + return CAN_TRY_PIVOT; + } + } + } + } + } + + return DONT_PIVOT; +} + +bool32 CanKnockOffItem(u32 battler, u32 item) +{ + if (item == ITEM_NONE) + return FALSE; + + if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_BATTLE_TOWER + | BATTLE_TYPE_LINK + | (B_TRAINERS_KNOCK_OFF_ITEMS == TRUE ? BATTLE_TYPE_TRAINER : 0) + )) && GetBattlerSide(battler) == B_SIDE_PLAYER) + return FALSE; + + if (AI_DATA->abilities[battler] == ABILITY_STICKY_HOLD) + return FALSE; + + if (!CanBattlerGetOrLoseItem(battler, item)) + return FALSE; + + return TRUE; +} + +// status checks +bool32 IsBattlerIncapacitated(u32 battler, u32 ability) +{ + if ((gBattleMons[battler].status1 & STATUS1_FREEZE) && !HasThawingMove(battler)) + return TRUE; // if battler has thawing move we assume they will definitely use it, and thus being frozen should be neglected + + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + return TRUE; + + if (gBattleMons[battler].status2 & STATUS2_RECHARGE || (ability == ABILITY_TRUANT && gDisableStructs[battler].truantCounter != 0)) + return TRUE; + + return FALSE; +} + +bool32 AI_CanSleep(u32 battler, u32 ability) +{ + if (ability == ABILITY_INSOMNIA + || ability == ABILITY_VITAL_SPIRIT + || ability == ABILITY_COMATOSE + || gBattleMons[battler].status1 & STATUS1_ANY + || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD + || (gFieldStatuses & (STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN)) + || IsAbilityStatusProtected(battler)) + return FALSE; + return TRUE; +} + +bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) +{ + if (!AI_CanSleep(battlerDef, defAbility) + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) // shouldn't try to sleep mon that partner is trying to make sleep + return FALSE; + return TRUE; +} + +static bool32 AI_CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 move) +{ + u32 ability = AI_DATA->abilities[battlerDef]; + + if (!(CanPoisonType(battlerAtk, battlerDef)) + || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD + || gBattleMons[battlerDef].status1 & STATUS1_ANY + || ability == ABILITY_IMMUNITY + || ability == ABILITY_COMATOSE + || AI_IsAbilityOnSide(battlerDef, ABILITY_PASTEL_VEIL) + || gBattleMons[battlerDef].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battlerDef) + || AI_IsTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN)) + return FALSE; + return TRUE; +} + +bool32 ShouldPoisonSelf(u32 battler, u32 ability) +{ + if (AI_CanBePoisoned(battler, battler, 0) && ( + ability == ABILITY_MARVEL_SCALE + || ability == ABILITY_POISON_HEAL + || ability == ABILITY_QUICK_FEET + || ability == ABILITY_MAGIC_GUARD + || (ability == ABILITY_TOXIC_BOOST && HasMoveWithCategory(battler, DAMAGE_CATEGORY_PHYSICAL)) + || (ability == ABILITY_GUTS && HasMoveWithCategory(battler, DAMAGE_CATEGORY_PHYSICAL)) + || HasMoveEffect(battler, EFFECT_FACADE) + || HasMoveEffect(battler, EFFECT_PSYCHO_SHIFT))) + return TRUE; // battler can be poisoned and has move/ability that synergizes with being poisoned + return FALSE; +} + +bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) +{ + if (!AI_CanBePoisoned(battlerAtk, battlerDef, move) + || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0 + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) + return FALSE; + else if (defAbility != ABILITY_CORROSION && (IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON) || IS_BATTLER_OF_TYPE(battlerDef, TYPE_STEEL))) + return FALSE; + else if (IsValidDoubleBattle(battlerAtk) && AI_DATA->abilities[BATTLE_PARTNER(battlerDef)] == ABILITY_PASTEL_VEIL) + return FALSE; + + return TRUE; +} + +static bool32 AI_CanBeParalyzed(u32 battler, u32 ability) +{ + if (ability == ABILITY_LIMBER + || ability == ABILITY_COMATOSE + || IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC) + || gBattleMons[battler].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battler)) + return FALSE; + return TRUE; +} + +bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) +{ + if (!AI_CanBeParalyzed(battlerDef, defAbility) + || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0 + || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) + return FALSE; + return TRUE; +} + +bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability) +{ + if ((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + || (ability == ABILITY_OWN_TEMPO && !DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battlerAtk], move)) + || (IsBattlerGrounded(battlerDef) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move)) + return FALSE; + return TRUE; +} + +bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) +{ + if (gMovesInfo[move].target == MOVE_TARGET_FOES_AND_ALLY + && AI_CanBeConfused(battlerAtk, battlerDef, move, defAbility) + && !AI_CanBeConfused(battlerAtk, BATTLE_PARTNER(battlerDef), move, AI_DATA->abilities[BATTLE_PARTNER(battlerDef)])) + return FALSE; + + if (!AI_CanBeConfused(battlerAtk, battlerDef, move, defAbility) + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + return FALSE; + + return TRUE; +} + +bool32 AI_CanBeBurned(u32 battler, u32 ability) +{ + if (ability == ABILITY_WATER_VEIL + || ability == ABILITY_WATER_BUBBLE + || ability == ABILITY_COMATOSE + || IS_BATTLER_OF_TYPE(battler, TYPE_FIRE) + || gBattleMons[battler].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battler) + || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) + return FALSE; + return TRUE; +} + +bool32 AI_CanGetFrostbite(u32 battler, u32 ability) +{ + if (ability == ABILITY_MAGMA_ARMOR + || ability == ABILITY_COMATOSE + || IS_BATTLER_OF_TYPE(battler, TYPE_ICE) + || gBattleMons[battler].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battler) + || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) + return FALSE; + return TRUE; +} + +bool32 ShouldBurnSelf(u32 battler, u32 ability) +{ + if (AI_CanBeBurned(battler, ability) && ( + ability == ABILITY_QUICK_FEET + || ability == ABILITY_HEATPROOF + || ability == ABILITY_MAGIC_GUARD + || (ability == ABILITY_FLARE_BOOST && HasMoveWithCategory(battler, DAMAGE_CATEGORY_SPECIAL)) + || (ability == ABILITY_GUTS && HasMoveWithCategory(battler, DAMAGE_CATEGORY_PHYSICAL)) + || HasMoveEffect(battler, EFFECT_FACADE) + || HasMoveEffect(battler, EFFECT_PSYCHO_SHIFT))) + return TRUE; + return FALSE; +} + +bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) +{ + if (!AI_CanBeBurned(battlerDef, defAbility) + || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0 + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove)) + { + return FALSE; + } + return TRUE; +} + +bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) +{ + if (!AI_CanGetFrostbite(battlerDef, defAbility) + || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0 + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove)) + { + return FALSE; + } + return TRUE; +} + +bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility) +{ + if ((gBattleMons[battlerDef].status2 & STATUS2_INFATUATION) + || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0 + || defAbility == ABILITY_OBLIVIOUS + || !AreBattlersOfOppositeGender(battlerAtk, battlerDef) + || AI_IsAbilityOnSide(battlerDef, ABILITY_AROMA_VEIL)) + return FALSE; + return TRUE; +} + +u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move) +{ + if (((!IsMoldBreakerTypeAbility(AI_DATA->abilities[battlerAtk]) && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS)) + || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER)) // Opponent goes first + { + return 0; + } + else if ((atkAbility == ABILITY_SERENE_GRACE + || gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS + || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION + || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + || ((AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) && CanTargetFaintAi(battlerDef, battlerAtk))) + { + return 2; // good idea to flinch + } + + return 0; // don't try to flinch +} + +bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move) +{ + if (IsBattlerTrapped(battlerDef, TRUE)) + return FALSE; + + if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef])) + return TRUE; // battler is taking secondary damage with low HP + + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + { + if (!CanTargetFaintAi(battlerDef, battlerAtk)) + return TRUE; // attacker goes first and opponent can't kill us + } + + return FALSE; +} + +bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move) +{ + if ((!gDisableStructs[battlerAtk].isFirstTurn && MoveHasAdditionalEffectWithChance(move, MOVE_EFFECT_FLINCH, 100)) + || AI_DATA->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS + || AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND + || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || (!IsMoldBreakerTypeAbility(AI_DATA->abilities[battlerAtk]) + && (AI_DATA->abilities[battlerDef] == ABILITY_SHIELD_DUST || AI_DATA->abilities[battlerDef] == ABILITY_INNER_FOCUS))) + return FALSE; + + return TRUE; +} + +static u32 FindMoveUsedXTurnsAgo(u32 battlerId, u32 x) +{ + s32 i, index = BATTLE_HISTORY->moveHistoryIndex[battlerId]; + for (i = 0; i < x; i++) + { + if (--index < 0) + index = AI_MOVE_HISTORY_COUNT - 1; + } + return BATTLE_HISTORY->moveHistory[battlerId][index]; +} + +bool32 IsWakeupTurn(u32 battler) +{ + // Check if rest was used 2 turns ago + if ((gBattleMons[battler].status1 & STATUS1_SLEEP) == 1 && FindMoveUsedXTurnsAgo(battler, 2) == MOVE_REST) + return TRUE; + else // no way to know + return FALSE; +} + +bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof) +{ + struct Pokemon *party; + u32 i; + + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = 0; i < PARTY_SIZE; i++) + { + if (checkSoundproof && GetMonAbility(&party[i]) == ABILITY_SOUNDPROOF) + continue; + + if (GetMonData(&party[i], MON_DATA_STATUS) != STATUS1_NONE) + return TRUE; + } + + return FALSE; +} + +u32 GetBattlerSideSpeedAverage(u32 battler) +{ + u32 speed1 = 0; + u32 speed2 = 0; + u32 numBattlersAlive = 0; + + if (IsBattlerAlive(battler)) + { + speed1 = AI_DATA->speedStats[battler]; + numBattlersAlive++; + } + + if (IsDoubleBattle() && IsBattlerAlive(BATTLE_PARTNER(battler))) + { + speed2 = AI_DATA->speedStats[BATTLE_PARTNER(battler)]; + numBattlersAlive++; + } + + return (speed1 + speed2) / numBattlersAlive; +} + +bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 moveIndex) +{ + if (recoilDmg >= gBattleMons[battlerAtk].hp //Recoil kills attacker + && CountUsablePartyMons(battlerDef) != 0) //Foe has more than 1 target left + { + if (recoilDmg >= gBattleMons[battlerDef].hp && !CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return TRUE; //If it's the only KO move then just use it + else + return FALSE; //Not as good to use move if you'll faint and not win + } + + return TRUE; +} + +bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage) +{ + if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) + { + // using item or user goes first + u32 healPercent = (gMovesInfo[move].argument == 0) ? 50 : gMovesInfo[move].argument; + s32 healDmg = (healPercent * damage) / 100; + + if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) + healDmg = 0; + + if (CanTargetFaintAi(battlerDef, battlerAtk) + && !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healDmg, 0)) + return TRUE; // target can faint attacker unless they heal + else if (!CanTargetFaintAi(battlerDef, battlerAtk) && AI_DATA->hpPercents[battlerAtk] < 60 && (Random() % 3)) + return TRUE; // target can't faint attacker at all, attacker health is about half, 2/3rds rate of encouraging healing + } + else + { + // opponent goes first + if (!CanTargetFaintAi(battlerDef, battlerAtk)) + return TRUE; + } + + return FALSE; +} + +bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent) +{ + if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) + { + // using item or user going first + s32 damage = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + s32 healAmount = (healPercent * damage) / 100; + if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) + healAmount = 0; + + if (CanTargetFaintAi(battlerDef, battlerAtk) + && !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healAmount, 0)) + return TRUE; // target can faint attacker unless they heal + else if (!CanTargetFaintAi(battlerDef, battlerAtk) && AI_DATA->hpPercents[battlerAtk] < 60 && (Random() % 3)) + return TRUE; // target can't faint attacker at all, attacker health is about half, 2/3rds rate of encouraging healing + } + return FALSE; +} + +bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect) +{ + u32 atkSide = GetBattlerSide(battlerAtk); + + if (HasMoveEffect(battlerDef, EFFECT_BRICK_BREAK)) // Don't waste a turn if screens will be broken + return FALSE; + + switch (moveEffect) + { + case EFFECT_AURORA_VEIL: + // Use only in Hail and only if AI doesn't already have Reflect, Light Screen or Aurora Veil itself active. + if ((AI_GetWeather(AI_DATA) & (B_WEATHER_HAIL | B_WEATHER_SNOW)) + && !(gSideStatuses[atkSide] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL))) + return TRUE; + break; + case EFFECT_REFLECT: + // Use only if the player has a physical move and AI doesn't already have Reflect itself active. + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) + && !(gSideStatuses[atkSide] & SIDE_STATUS_REFLECT)) + return TRUE; + break; + case EFFECT_LIGHT_SCREEN: + // Use only if the player has a special move and AI doesn't already have Light Screen itself active. + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) + && !(gSideStatuses[atkSide] & SIDE_STATUS_LIGHTSCREEN)) + return TRUE; + break; + } + + return FALSE; +} + +// Partner Logic +bool32 IsValidDoubleBattle(u32 battlerAtk) +{ + if (IsDoubleBattle() + && ((IsBattlerAlive(BATTLE_OPPOSITE(battlerAtk)) && IsBattlerAlive(BATTLE_PARTNER(BATTLE_OPPOSITE(battlerAtk)))) || IsBattlerAlive(BATTLE_PARTNER(battlerAtk)))) + return TRUE; + return FALSE; +} + +u32 GetAllyChosenMove(u32 battlerId) +{ + u32 partnerBattler = BATTLE_PARTNER(battlerId); + + if (!IsBattlerAlive(partnerBattler) || !IsAiBattlerAware(partnerBattler)) + return MOVE_NONE; + else if (partnerBattler > battlerId) // Battler with the lower id chooses the move first. + return gLastMoves[partnerBattler]; + else + return gBattleMons[partnerBattler].moves[gBattleStruct->chosenMovePositions[partnerBattler]]; +} + +//PARTNER_MOVE_EFFECT_IS_SAME +bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (gMovesInfo[move].effect == gMovesInfo[partnerMove].effect + && partnerMove != MOVE_NONE + && gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef) + { + return TRUE; + } + return FALSE; +} + +//PARTNER_MOVE_EFFECT_IS_SAME_NO_TARGET +bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (gMovesInfo[move].effect == gMovesInfo[partnerMove].effect + && partnerMove != MOVE_NONE) + return TRUE; + return FALSE; +} + +//PARTNER_MOVE_EFFECT_IS_STATUS_SAME_TARGET +bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (partnerMove != MOVE_NONE + && gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef + && (gMovesInfo[partnerMove].effect == EFFECT_SLEEP + || gMovesInfo[partnerMove].effect == EFFECT_POISON + || gMovesInfo[partnerMove].effect == EFFECT_TOXIC + || gMovesInfo[partnerMove].effect == EFFECT_PARALYZE + || gMovesInfo[partnerMove].effect == EFFECT_WILL_O_WISP + || gMovesInfo[partnerMove].effect == EFFECT_YAWN)) + return TRUE; + return FALSE; +} + +bool32 IsMoveEffectWeather(u32 move) +{ + if (move != MOVE_NONE + && (gMovesInfo[move].effect == EFFECT_SUNNY_DAY + || gMovesInfo[move].effect == EFFECT_RAIN_DANCE + || gMovesInfo[move].effect == EFFECT_SANDSTORM + || gMovesInfo[move].effect == EFFECT_HAIL + || gMovesInfo[move].effect == EFFECT_SNOWSCAPE)) + return TRUE; + return FALSE; +} + +//PARTNER_MOVE_EFFECT_IS_TERRAIN +bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (partnerMove != MOVE_NONE + && (gMovesInfo[partnerMove].effect == EFFECT_GRASSY_TERRAIN + || gMovesInfo[partnerMove].effect == EFFECT_MISTY_TERRAIN + || gMovesInfo[partnerMove].effect == EFFECT_ELECTRIC_TERRAIN + || gMovesInfo[partnerMove].effect == EFFECT_PSYCHIC_TERRAIN)) + return TRUE; + + return FALSE; +} + +//PARTNER_MOVE_IS_TAILWIND_TRICKROOM +bool32 PartnerMoveIs(u32 battlerAtkPartner, u32 partnerMove, u32 moveCheck) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (partnerMove != MOVE_NONE && partnerMove == moveCheck) + return TRUE; + return FALSE; +} + +//PARTNER_MOVE_IS_SAME +bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (partnerMove != MOVE_NONE && move == partnerMove && gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef) + return TRUE; + return FALSE; +} + +//PARTNER_MOVE_IS_SAME_NO_TARGET +bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + if (partnerMove != MOVE_NONE && move == partnerMove) + return TRUE; + return FALSE; +} + +bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move) +{ + u32 i; + s32 firstId, lastId; + struct Pokemon* party; + bool32 hasStatus = FALSE; + bool32 needHealing = FALSE; + + GetAIPartyIndexes(battlerAtk, &firstId, &lastId); + + if (GetBattlerSide(battlerAtk) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (CountUsablePartyMons(battlerAtk) == 0 + && (CanTargetFaintAi(battlerDef, battlerAtk) || BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]))) + return FALSE; // Don't heal if last mon and will faint + + for (i = 0; i < PARTY_SIZE; i++) + { + u32 currHp = GetMonData(&party[i], MON_DATA_HP); + u32 maxHp = GetMonData(&party[i], MON_DATA_MAX_HP); + + if (!GetMonData(&party[i], MON_DATA_IS_EGG, NULL) && currHp > 0) + { + if ((currHp * 100) / maxHp < 65 // Less than 65% health remaining + && i >= firstId && i < lastId) // Can only switch to mon on your team + { + needHealing = TRUE; + } + + if (GetMonData(&party[i], MON_DATA_STATUS, NULL) != STATUS1_NONE) + { + if (move != MOVE_HEAL_BELL || GetMonAbility(&party[i]) != ABILITY_SOUNDPROOF) + hasStatus = TRUE; + } + } + } + + if (!IsDoubleBattle()) + { + switch (gMovesInfo[move].effect) + { + case EFFECT_WISH: + if (needHealing) + return TRUE; + break; + case EFFECT_HEAL_BELL: + if (hasStatus) + return TRUE; + } + } + else + { + switch (gMovesInfo[move].effect) + { + case EFFECT_WISH: + return ShouldRecover(battlerAtk, battlerDef, move, 50); // Switch recovery isn't good idea in doubles + case EFFECT_HEAL_BELL: + if (hasStatus) + return TRUE; + } + } + + return FALSE; +} + +#define SIZE_G_BATTLE_MONS (sizeof(struct BattlePokemon) * MAX_BATTLERS_COUNT) + +struct BattlePokemon *AllocSaveBattleMons(void) +{ + struct BattlePokemon *savedBattleMons = Alloc(SIZE_G_BATTLE_MONS); + memcpy(savedBattleMons, gBattleMons, SIZE_G_BATTLE_MONS); + return savedBattleMons; +} + +void FreeRestoreBattleMons(struct BattlePokemon *savedBattleMons) +{ + memcpy(gBattleMons, savedBattleMons, SIZE_G_BATTLE_MONS); + Free(savedBattleMons); +} + +// party logic +s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, bool8 isPartyMonAttacker) +{ + s32 dmg; + u8 effectiveness; + struct BattlePokemon *savedBattleMons = AllocSaveBattleMons(); + if(isPartyMonAttacker) + gBattleMons[battlerAtk] = switchinCandidate; + else + gBattleMons[battlerDef] = switchinCandidate; + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE, AI_GetWeather(AI_DATA)); + FreeRestoreBattleMons(savedBattleMons); + return dmg; +} + +s32 CountUsablePartyMons(u32 battlerId) +{ + s32 battlerOnField1, battlerOnField2, i, ret; + struct Pokemon *party; + + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + battlerOnField1 = gBattlerPartyIndexes[battlerId]; + battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))]; + } + else // In singles there's only one battlerId by side. + { + battlerOnField1 = gBattlerPartyIndexes[battlerId]; + battlerOnField2 = gBattlerPartyIndexes[battlerId]; + } + + ret = 0; + for (i = 0; i < PARTY_SIZE; i++) + { + if (i != battlerOnField1 && i != battlerOnField2 + && GetMonData(&party[i], MON_DATA_HP) != 0 + && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG) + { + ret++; + } + } + + return ret; +} + +bool32 IsPartyFullyHealedExceptBattler(u32 battlerId) +{ + struct Pokemon *party; + u32 i; + + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = 0; i < PARTY_SIZE; i++) + { + if (i != gBattlerPartyIndexes[battlerId] + && GetMonData(&party[i], MON_DATA_HP) != 0 + && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG + && GetMonData(&party[i], MON_DATA_HP) < GetMonData(&party[i], MON_DATA_MAX_HP)) + return FALSE; + } + return TRUE; +} + +bool32 PartyHasMoveCategory(u32 battlerId, u32 category) +{ + struct Pokemon *party = GetBattlerParty(battlerId); + u32 i, j; + + for (i = 0; i < PARTY_SIZE; i++) + { + if (GetMonData(&party[i], MON_DATA_HP, NULL) == 0) + continue; + + for (j = 0; j < MAX_MON_MOVES; j++) + { + u32 move = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL); + u32 pp = GetMonData(&party[i], MON_DATA_PP1 + j, NULL); + + if (pp > 0 && move != MOVE_NONE) + { + //TODO - handle photon geyser, light that burns the sky + if (gMovesInfo[move].category == category) + return TRUE; + } + } + } + + return FALSE; +} + +bool32 SideHasMoveCategory(u32 battlerId, u32 category) +{ + if (IsDoubleBattle()) + { + if (HasMoveWithCategory(battlerId, category) || HasMoveWithCategory(BATTLE_PARTNER(battlerId), category)) + return TRUE; + } + else + { + if (HasMoveWithCategory(battlerId, category)) + return TRUE; + } + return FALSE; +} + +bool32 IsAbilityOfRating(u32 ability, s8 rating) +{ + if (gAbilitiesInfo[ability].aiRating >= rating) + return TRUE; + return FALSE; +} + +static const u16 sRecycleEncouragedItems[] = +{ + ITEM_CHESTO_BERRY, + ITEM_LUM_BERRY, + ITEM_STARF_BERRY, + ITEM_SITRUS_BERRY, + ITEM_MICLE_BERRY, + ITEM_CUSTAP_BERRY, + ITEM_MENTAL_HERB, + ITEM_FOCUS_SASH, + // TODO expand this +}; + +// Its assumed that the berry is strategically given, so no need to check benefits of the berry +bool32 IsStatBoostingBerry(u32 item) +{ + switch (item) + { + case ITEM_LIECHI_BERRY: + case ITEM_GANLON_BERRY: + case ITEM_SALAC_BERRY: + case ITEM_PETAYA_BERRY: + case ITEM_APICOT_BERRY: + //case ITEM_LANSAT_BERRY: + case ITEM_STARF_BERRY: + case ITEM_MICLE_BERRY: + return TRUE; + default: + return FALSE; + } +} + +bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item) +{ + switch (item) + { + case ITEM_ORAN_BERRY: + if (gBattleMons[battlerAtk].maxHP <= 50) + return TRUE; // Only worth it in the early game + return FALSE; + case ITEM_SITRUS_BERRY: + case ITEM_FIGY_BERRY: + case ITEM_WIKI_BERRY: + case ITEM_MAGO_BERRY: + case ITEM_AGUAV_BERRY: + case ITEM_IAPAPA_BERRY: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsRecycleEncouragedItem(u32 item) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sRecycleEncouragedItems); i++) + { + if (item == sRecycleEncouragedItems[i]) + return TRUE; + } + return FALSE; +} + +void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score) +{ + u32 noOfHitsToFaint = NoOfHitsForTargetToFaintAI(battlerDef, battlerAtk); + u32 aiIsFaster = GetWhichBattlerFaster(battlerAtk, battlerDef, TRUE) == AI_IS_FASTER; + u32 shouldSetUp = ((noOfHitsToFaint >= 2 && aiIsFaster) || (noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS); + + if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) + return; + + // Don't increase stat if AI is at +4 + if (gBattleMons[battlerAtk].statStages[statId] >= MAX_STAT_STAGE - 2) + return; + + // Don't increase stat if AI has less then 70% HP and number of hits isn't known + if (AI_DATA->hpPercents[battlerAtk] < 70 && noOfHitsToFaint == UNKNOWN_NO_OF_HITS) + return; + + // Don't set up if AI is dead to residual damage from weather + if (GetBattlerSecondaryDamage(battlerAtk) >= gBattleMons[battlerAtk].hp) + return; + + // Don't increase stats if opposing battler has Opportunist + if (AI_DATA->abilities[battlerDef] == ABILITY_OPPORTUNIST) + return; + + switch (statId) + { + case STAT_CHANGE_ATK: + if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) && shouldSetUp) + ADJUST_SCORE_PTR(DECENT_EFFECT); + break; + case STAT_CHANGE_DEF: + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + { + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + ADJUST_SCORE_PTR(DECENT_EFFECT); + else + ADJUST_SCORE_PTR(WEAK_EFFECT); + } + break; + case STAT_CHANGE_SPEED: + if ((noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS) + ADJUST_SCORE_PTR(DECENT_EFFECT); + break; + case STAT_CHANGE_SPATK: + if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL) && shouldSetUp) + ADJUST_SCORE_PTR(DECENT_EFFECT); + break; + case STAT_CHANGE_SPDEF: + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + { + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + ADJUST_SCORE_PTR(DECENT_EFFECT); + else + ADJUST_SCORE_PTR(WEAK_EFFECT); + } + break; + case STAT_CHANGE_ATK_2: + if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) && shouldSetUp) + ADJUST_SCORE_PTR(GOOD_EFFECT); + break; + case STAT_CHANGE_DEF_2: + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + { + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + ADJUST_SCORE_PTR(GOOD_EFFECT); + else + ADJUST_SCORE_PTR(DECENT_EFFECT); + } + break; + case STAT_CHANGE_SPEED_2: + if ((noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS) + ADJUST_SCORE_PTR(GOOD_EFFECT); + break; + case STAT_CHANGE_SPATK_2: + if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL) && shouldSetUp) + ADJUST_SCORE_PTR(GOOD_EFFECT); + break; + case STAT_CHANGE_SPDEF_2: + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + { + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + ADJUST_SCORE_PTR(GOOD_EFFECT); + else + ADJUST_SCORE_PTR(DECENT_EFFECT); + } + break; + case STAT_CHANGE_ACC: + if (gBattleMons[battlerAtk].statStages[STAT_ACC] <= 3) // Increase only if necessary + ADJUST_SCORE_PTR(DECENT_EFFECT); + break; + case STAT_CHANGE_EVASION: + if (noOfHitsToFaint > 3 || noOfHitsToFaint == UNKNOWN_NO_OF_HITS) + ADJUST_SCORE_PTR(GOOD_EFFECT); + else + ADJUST_SCORE_PTR(DECENT_EFFECT); + break; + } +} + +void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) +{ + if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PSN || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + return; + + if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove) && AI_DATA->hpPercents[battlerDef] > 20) + { + if (!HasDamagingMove(battlerDef)) + ADJUST_SCORE_PTR(DECENT_EFFECT); + + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT)) + ADJUST_SCORE_PTR(WEAK_EFFECT); // stall tactic + + if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PSN_ANY) + || HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH) + || AI_DATA->abilities[battlerAtk] == ABILITY_MERCILESS) + ADJUST_SCORE_PTR(DECENT_EFFECT); + else + ADJUST_SCORE_PTR(WEAK_EFFECT); + } +} + +void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) +{ + if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_BRN || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + return; + + if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) + { + ADJUST_SCORE_PTR(WEAK_EFFECT); // burning is good + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + { + if (CanTargetFaintAi(battlerDef, battlerAtk)) + ADJUST_SCORE_PTR(DECENT_EFFECT); // burning the target to stay alive is cool + } + + if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN) + || HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN)) + ADJUST_SCORE_PTR(WEAK_EFFECT); + } +} + +void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) +{ + if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PAR || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + return; + + if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) + { + u32 atkSpeed = AI_DATA->speedStats[battlerAtk]; + u32 defSpeed = AI_DATA->speedStats[battlerDef]; + + if ((defSpeed >= atkSpeed && defSpeed / 2 < atkSpeed) // You'll go first after paralyzing foe + || HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PARALYSIS) + || (HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY)) // filter out Fake Out + || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION + || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + ADJUST_SCORE_PTR(GOOD_EFFECT); + else + ADJUST_SCORE_PTR(DECENT_EFFECT); + } +} + +void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) +{ + if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_SLP || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + return; + + if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) + ADJUST_SCORE_PTR(DECENT_EFFECT); + else + return; + + if ((HasMoveEffect(battlerAtk, EFFECT_DREAM_EATER) || HasMoveEffect(battlerAtk, EFFECT_NIGHTMARE)) + && !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) + ADJUST_SCORE_PTR(WEAK_EFFECT); + + if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP) + || HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP)) + ADJUST_SCORE_PTR(WEAK_EFFECT); +} + +void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) +{ + if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_CONFUSION || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + return; + + if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CURE_CONFUSION + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CURE_STATUS) + { + if (gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS + || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION + || (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY))) + ADJUST_SCORE_PTR(GOOD_EFFECT); + else + ADJUST_SCORE_PTR(DECENT_EFFECT); + } +} + +void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) +{ + if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + + if (AI_CanGiveFrostbite(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) + { + ADJUST_SCORE_PTR(WEAK_EFFECT); // frostbite is good + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + { + if (CanTargetFaintAi(battlerDef, battlerAtk)) + ADJUST_SCORE_PTR(DECENT_EFFECT); // frostbiting the target to stay alive is cool + } + + if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE) + || HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE)) + ADJUST_SCORE_PTR(WEAK_EFFECT); + } +} + +bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move) +{ + if (gMovesInfo[move].makesContact + && ability != ABILITY_LONG_REACH + && holdEffect != HOLD_EFFECT_PROTECTIVE_PADS) + return TRUE; + return FALSE; +} + +//TODO - this could use some more sophisticated logic +bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove) +{ + // simple logic. just upgrades chosen move to z move if possible, unless regular move would kill opponent + if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && battlerDef == BATTLE_PARTNER(battlerAtk)) + return FALSE; //don't use z move on partner + if (gBattleStruct->zmove.used[battlerAtk]) + return FALSE; //cant use z move twice + + // TODO: Z-moves + if (FALSE /* IsViableZMove(battlerAtk, chosenMove) */) + { + u8 effectiveness; + + if (gBattleMons[battlerDef].ability == ABILITY_DISGUISE + && (gBattleMons[battlerDef].species == SPECIES_MIMIKYU_DISGUISED || gBattleMons[battlerDef].species == SPECIES_MIMIKYU_TOTEM_DISGUISED)) + return FALSE; // Don't waste a Z-Move busting disguise + if (gBattleMons[battlerDef].ability == ABILITY_ICE_FACE && gBattleMons[battlerDef].species == SPECIES_EISCUE_ICE_FACE && IS_MOVE_PHYSICAL(chosenMove)) + return FALSE; // Don't waste a Z-Move busting Ice Face + + if (IS_MOVE_STATUS(chosenMove) && !IS_MOVE_STATUS(gBattleStruct->zmove.chosenZMove)) + return FALSE; + else if (!IS_MOVE_STATUS(chosenMove) && IS_MOVE_STATUS(gBattleStruct->zmove.chosenZMove)) + return FALSE; + + if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamageSaveBattlers(chosenMove, battlerAtk, battlerDef, &effectiveness, FALSE) >= gBattleMons[battlerDef].hp) + return FALSE; // don't waste damaging z move if can otherwise faint target + + return TRUE; + } + + return FALSE; +} + +bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId) +{ + return (gBattleMons[battlerId].status1 & STATUS1_SLEEP) || AI_DATA->abilities[battlerId] == ABILITY_COMATOSE; +} + +s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle) +{ + if (isDoubleBattle) + return min(CountPositiveStatStages(battlerDef) + CountPositiveStatStages(BATTLE_PARTNER(battlerDef)), 7); + else + return min(CountPositiveStatStages(battlerDef), 4); +} + +bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef) +{ + u8 i; + // Want to copy positive stat changes + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerDef].statStages[i] > gBattleMons[battlerAtk].statStages[i]) + { + switch (i) + { + case STAT_ATK: + return (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)); + case STAT_SPATK: + return (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)); + case STAT_ACC: + case STAT_EVASION: + case STAT_SPEED: + return TRUE; + case STAT_DEF: + case STAT_SPDEF: + return (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL); + } + } + } + + return FALSE; +} + +//TODO - track entire opponent party data to determine hazard effectiveness +bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData) +{ + if (aiData->abilities[battlerDef] == ABILITY_MAGIC_BOUNCE + || CountUsablePartyMons(battlerDef) == 0 + || HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) + || HasMoveEffect(battlerDef, EFFECT_DEFOG)) + return FALSE; + + return TRUE; +} + +void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) +{ + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) + ADJUST_SCORE_PTR(GOOD_EFFECT); + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerDef) != 0) + ADJUST_SCORE_PTR(-2); + + if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE && AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) + ADJUST_SCORE_PTR(-10); + if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE) + ADJUST_SCORE_PTR(GOOD_EFFECT); + + if (gStatuses3[battlerAtk] & STATUS3_LEECHSEED) + ADJUST_SCORE_PTR(DECENT_EFFECT); + if (gStatuses3[battlerDef] & STATUS3_LEECHSEED) + ADJUST_SCORE_PTR(-2); +} diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index f79d2a2df..8d0c345cc 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -7,17 +7,21 @@ #include "pokeball.h" #include "random.h" #include "battle.h" +#include "battle_ai_main.h" +#include "battle_ai_util.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_message.h" #include "battle_interface.h" #include "battle_tower.h" #include "battle_gfx_sfx_util.h" -#include "battle_ai_script_commands.h" #include "battle_ai_switch_items.h" +#include "party_menu.h" #include "trainer_tower.h" +#include "constants/battle_ai.h" #include "constants/battle_anim.h" #include "constants/moves.h" +#include "constants/party_menu.h" #include "constants/songs.h" #include "constants/sound.h" @@ -35,6 +39,7 @@ static void OpponentHandleIntroTrainerBallThrow(u32 battler); static void OpponentHandleDrawPartyStatusSummary(u32 battler); static void OpponentHandleBattleAnimation(u32 battler); static void OpponentHandleEndLinkBattle(u32 battler); +static u8 CountAIAliveNonEggMonsExcept(u8 slotToIgnore); static void OpponentBufferRunCommand(u32 battler); static void SwitchIn_HandleSoundAndEnd(u32 battler); @@ -356,50 +361,117 @@ static void OpponentHandleChooseMove(u32 battler) u8 chosenMoveId; struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); - if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER)) + if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER) + || IsWildMonSmart()) { - // TODO: update with AI refactoring - BattleAI_SetupAIData(battler); - chosenMoveId = BattleAI_ChooseMoveOrAction(); - + chosenMoveId = gBattleStruct->aiMoveOrAction[battler]; + gBattlerTarget = gBattleStruct->aiChosenTarget[battler]; switch (chosenMoveId) { case AI_CHOICE_WATCH: - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SAFARI_WATCH_CAREFULLY, 0); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SAFARI_WATCH_CAREFULLY, 0); break; case AI_CHOICE_FLEE: - BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_RUN, 0); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_RUN, 0); + break; + case AI_CHOICE_SWITCH: + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, 0xFFFF); + break; + case 6: + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 15, gBattlerTarget); break; default: - if (gMovesInfo[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) - gBattlerTarget = battler; - if (gMovesInfo[moveInfo->moves[chosenMoveId]].target & MOVE_TARGET_BOTH) { - gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) - gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + u16 chosenMove = moveInfo->moves[chosenMoveId]; + bool32 isSecondTrainer = (GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT) && (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT; + u16 trainerId = isSecondTrainer ? gTrainerBattleOpponent_B : gTrainerBattleOpponent_A; + const struct TrainerMon *party = GetTrainerPartyFromId(trainerId); + bool32 shouldDynamax = FALSE; + if (party != NULL) + shouldDynamax = party[isSecondTrainer ? gBattlerPartyIndexes[battler] - MULTI_PARTY_SIZE : gBattlerPartyIndexes[battler]].shouldDynamax; + + if (GetBattlerMoveTargetType(battler, chosenMove) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) + gBattlerTarget = battler; + if (GetBattlerMoveTargetType(battler, chosenMove) & MOVE_TARGET_BOTH) + { + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + } + // TODO: Z-Moves + // if (ShouldUseZMove(battler, gBattlerTarget, chosenMove)) + // QueueZMove(battler, chosenMove); + // If opponent can Mega Evolve, do it. + if (CanMegaEvolve(battler)) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_MEGA_EVOLUTION) | (gBattlerTarget << 8)); + // If opponent can Ultra Burst, do it. + else if (CanUltraBurst(battler)) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_ULTRA_BURST) | (gBattlerTarget << 8)); + // If opponent can Dynamax and is allowed in the partydata, do it. + else if (CanDynamax(battler) && shouldDynamax) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_DYNAMAX) | (gBattlerTarget << 8)); + else + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (gBattlerTarget << 8)); } - BtlController_EmitTwoReturnValues(battler, 1, 10, (chosenMoveId) | (gBattlerTarget << 8)); break; } OpponentBufferExecCompleted(battler); } - else + else // Wild pokemon - use random move { u16 move; - + u8 target; do { chosenMoveId = Random() & 3; move = moveInfo->moves[chosenMoveId]; - } - while (move == MOVE_NONE); - if (gMovesInfo[move].target & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) - BtlController_EmitTwoReturnValues(battler, 1, 10, (chosenMoveId) | (battler << 8)); + } while (move == MOVE_NONE); + + if (GetBattlerMoveTargetType(battler, move) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (battler << 8)); else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - BtlController_EmitTwoReturnValues(battler, 1, 10, (chosenMoveId) | (GetBattlerAtPosition(Random() & 2) << 8)); + { + do { + target = GetBattlerAtPosition(Random() & 2); + } while (!CanTargetBattler(battler, target, move)); + + // Don't bother to loop through table if the move can't attack ally + if (B_WILD_NATURAL_ENEMIES == TRUE && !(gMovesInfo[move].target & MOVE_TARGET_BOTH)) + { + u16 i, speciesAttacker, speciesTarget, isPartnerEnemy = FALSE; + static const u16 naturalEnemies[][2] = + { + // Attacker Target + {SPECIES_ZANGOOSE, SPECIES_SEVIPER}, + {SPECIES_SEVIPER, SPECIES_ZANGOOSE}, + {SPECIES_HEATMOR, SPECIES_DURANT}, + {SPECIES_DURANT, SPECIES_HEATMOR}, + {SPECIES_SABLEYE, SPECIES_CARBINK}, + {SPECIES_MAREANIE, SPECIES_CORSOLA}, + }; + speciesAttacker = gBattleMons[battler].species; + speciesTarget = gBattleMons[GetBattlerAtPosition(BATTLE_PARTNER(battler))].species; + + for (i = 0; i < ARRAY_COUNT(naturalEnemies); i++) + { + if (speciesAttacker == naturalEnemies[i][0] && speciesTarget == naturalEnemies[i][1]) + { + isPartnerEnemy = TRUE; + break; + } + } + if (isPartnerEnemy && CanTargetBattler(battler, target, move)) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(BATTLE_PARTNER(battler)) << 8)); + else + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (target << 8)); + } + else + { + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (target << 8)); + } + } else - BtlController_EmitTwoReturnValues(battler, 1, 10, (chosenMoveId) | (GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) << 8)); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) << 8)); OpponentBufferExecCompleted(battler); } @@ -414,14 +486,20 @@ static void OpponentHandleChooseItem(u32 battler) static void OpponentHandleChoosePokemon(u32 battler) { s32 chosenMonId; + s32 pokemonInBattle = 1; - if (*(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) == PARTY_SIZE) + // Choosing Revival Blessing target + if ((gBattleResources->bufferA[battler][1] & 0xF) == PARTY_ACTION_CHOOSE_FAINTED_MON) { - chosenMonId = GetMostSuitableMonToSwitchInto(battler); - + chosenMonId = gSelectedMonPartyId = GetFirstFaintedPartyIndex(battler); + } + // Switching out + else if (*(gBattleStruct->AI_monToSwitchIntoId + battler) == PARTY_SIZE) + { + chosenMonId = GetMostSuitableMonToSwitchInto(battler, TRUE); if (chosenMonId == PARTY_SIZE) { - s32 battler1, battler2; + s32 battler1, battler2, firstId, lastId; if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) { @@ -431,24 +509,52 @@ static void OpponentHandleChoosePokemon(u32 battler) { battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); battler2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + pokemonInBattle = 2; } - for (chosenMonId = 0; chosenMonId < PARTY_SIZE; ++chosenMonId) - if (GetMonData(&gEnemyParty[chosenMonId], MON_DATA_HP) != 0 - && chosenMonId != gBattlerPartyIndexes[battler1] - && chosenMonId != gBattlerPartyIndexes[battler2]) + + GetAIPartyIndexes(battler, &firstId, &lastId); + + for (chosenMonId = (lastId-1); chosenMonId >= firstId; chosenMonId--) + { + if (IsValidForBattle(&gEnemyParty[chosenMonId]) + && chosenMonId != gBattlerPartyIndexes[battler1] + && chosenMonId != gBattlerPartyIndexes[battler2] + && (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON) + || chosenMonId != CalculateEnemyPartyCount() - 1 + || CountAIAliveNonEggMonsExcept(PARTY_SIZE) == pokemonInBattle)) + { break; + } + } } + *(gBattleStruct->monToSwitchIntoId + battler) = chosenMonId; } else { - chosenMonId = *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)); - *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = PARTY_SIZE; + chosenMonId = *(gBattleStruct->AI_monToSwitchIntoId + battler); + *(gBattleStruct->AI_monToSwitchIntoId + battler) = PARTY_SIZE; + *(gBattleStruct->monToSwitchIntoId + battler) = chosenMonId; } - *(gBattleStruct->monToSwitchIntoId + battler) = chosenMonId; - BtlController_EmitChosenMonReturnValue(battler, 1, chosenMonId, NULL); + BtlController_EmitChosenMonReturnValue(battler, BUFFER_B, chosenMonId, NULL); OpponentBufferExecCompleted(battler); } +static u8 CountAIAliveNonEggMonsExcept(u8 slotToIgnore) +{ + u16 i, count; + + for (i = 0, count = 0; i < PARTY_SIZE; i++) + { + if (i != slotToIgnore + && IsValidForBattle(&gEnemyParty[i])) + { + count++; + } + } + + return count; +} + static void OpponentHandleHealthBarUpdate(u32 battler) { BtlController_HandleHealthBarUpdate(battler, FALSE); diff --git a/src/battle_controllers.c b/src/battle_controllers.c index c20a3963c..87d76dfae 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -1,6 +1,7 @@ #include "global.h" #include "battle.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" +#include "battle_ai_util.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_interface.h" @@ -70,7 +71,8 @@ void SetUpBattleVars(void) gBattleControllerExecFlags = 0; ClearBattleAnimationVars(); ClearBattleMonForms(); - BattleAI_HandleItemUseBeforeAISetup(); + BattleAI_SetupItems(); + BattleAI_SetupFlags(); } void InitBattleControllers(void) diff --git a/src/battle_main.c b/src/battle_main.c index 681278221..6dd00222e 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -1,8 +1,9 @@ #include "global.h" #include "gflib.h" #include "battle.h" +#include "battle_ai_main.h" +#include "battle_ai_util.h" #include "battle_anim.h" -#include "battle_ai_script_commands.h" #include "battle_controllers.h" #include "battle_interface.h" #include "battle_main.h" diff --git a/src/battle_message.c b/src/battle_message.c index d96517291..c4a61709b 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -2149,15 +2149,15 @@ const u16 gSafariReactionStringIds[NUM_SAFARI_REACTIONS] = [B_MSG_MON_EATING] = STRINGID_PKMNEATING }; -const u16 gTrainerItemCuredStatusStringIds[] = -{ - [AI_HEAL_CONFUSION] = STRINGID_PKMNSITEMSNAPPEDOUT, - [AI_HEAL_PARALYSIS] = STRINGID_PKMNSITEMCUREDPARALYSIS, - [AI_HEAL_FREEZE] = STRINGID_PKMNSITEMDEFROSTEDIT, - [AI_HEAL_BURN] = STRINGID_PKMNSITEMHEALEDBURN, - [AI_HEAL_POISON] = STRINGID_PKMNSITEMCUREDPOISON, - [AI_HEAL_SLEEP] = STRINGID_PKMNSITEMWOKEIT -}; +// const u16 gTrainerItemCuredStatusStringIds[] = +// { +// [AI_HEAL_CONFUSION] = STRINGID_PKMNSITEMSNAPPEDOUT, +// [AI_HEAL_PARALYSIS] = STRINGID_PKMNSITEMCUREDPARALYSIS, +// [AI_HEAL_FREEZE] = STRINGID_PKMNSITEMDEFROSTEDIT, +// [AI_HEAL_BURN] = STRINGID_PKMNSITEMHEALEDBURN, +// [AI_HEAL_POISON] = STRINGID_PKMNSITEMCUREDPOISON, +// [AI_HEAL_SLEEP] = STRINGID_PKMNSITEMWOKEIT +// }; const u16 gBerryEffectStringIds[] = { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 6e6da5bf2..a38d2189e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -20,9 +20,10 @@ #include "trainer_pokemon_sprites.h" #include "field_specials.h" #include "battle.h" +#include "battle_ai_main.h" +#include "battle_ai_util.h" #include "battle_message.h" #include "battle_anim.h" -#include "battle_ai_script_commands.h" #include "battle_scripts.h" #include "reshow_battle_screen.h" #include "battle_controllers.h" @@ -1935,6 +1936,14 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA } #undef BENEFITS_FROM_LEEK +s32 GetCritHitChance(s32 critChanceIndex) +{ + if (critChanceIndex < 0) + return -1; + else + return sCriticalHitChance[critChanceIndex]; +} + static void Cmd_critcalc(void) { CMD_ARGS(); diff --git a/src/battle_util.c b/src/battle_util.c index bd4095489..dbb4332e5 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -11,6 +11,8 @@ #include "field_weather.h" #include "event_data.h" #include "battle.h" +#include "battle_ai_main.h" +#include "battle_ai_util.h" #include "battle_anim.h" #include "battle_dynamax.h" #include "battle_interface.h" @@ -19,7 +21,6 @@ #include "malloc.h" #include "constants/battle_anim.h" #include "battle_controllers.h" -#include "battle_ai_script_commands.h" #include "constants/battle.h" #include "constants/moves.h" #include "constants/items.h" @@ -30,11 +31,6 @@ #include "constants/battle_move_effects.h" #include "constants/battle_script_commands.h" -// TODO: remove when battle_ai_util -#define AI_THINKING_STRUCT (gBattleResources->ai) -#define BATTLE_HISTORY (gBattleResources->battleHistory) - - static bool32 TryRemoveScreens(u32 battler); static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler); static u32 GetFlingPowerFromItemId(u32 itemId); @@ -6860,37 +6856,72 @@ const uq4_12_t gTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES] #undef ______ #undef X -u8 GetMoveTarget(u16 move, u8 setTarget) + + + +u32 SetRandomTarget(u32 battler) +{ + u32 target; + static const u8 targets[2][2] = + { + [B_SIDE_PLAYER] = {B_POSITION_OPPONENT_LEFT, B_POSITION_OPPONENT_RIGHT}, + [B_SIDE_OPPONENT] = {B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT}, + }; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + target = GetBattlerAtPosition(targets[GetBattlerSide(battler)][Random() % 2]); + if (!IsBattlerAlive(target)) + target ^= BIT_FLANK; + } + else + { + target = GetBattlerAtPosition(targets[GetBattlerSide(battler)][0]); + } + + return target; +} + +u32 GetMoveTarget(u16 move, u8 setTarget) { u8 targetBattler = 0; - u8 moveTarget; - u8 side; + u32 moveTarget, side; if (setTarget != NO_TARGET_OVERRIDE) moveTarget = setTarget - 1; else - moveTarget = gMovesInfo[move].target; + moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move); + + // Special cases + if (move == MOVE_CURSE && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) + moveTarget = MOVE_TARGET_USER; switch (moveTarget) { case MOVE_TARGET_SELECTED: - side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; - if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) + side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker)); + if (IsAffectedByFollowMe(gBattlerAttacker, side, move)) + { targetBattler = gSideTimers[side].followmeTarget; + } else { - side = GetBattlerSide(gBattlerAttacker); - do - { - targetBattler = Random() % gBattlersCount; - } while (targetBattler == gBattlerAttacker || side == GetBattlerSide(targetBattler) || gAbsentBattlerFlags & gBitTable[targetBattler]); + targetBattler = SetRandomTarget(gBattlerAttacker); if (gMovesInfo[move].type == TYPE_ELECTRIC - && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_LIGHTNING_ROD, 0, 0) - && gBattleMons[targetBattler].ability != ABILITY_LIGHTNING_ROD) + && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_LIGHTNING_ROD) + && GetBattlerAbility(targetBattler) != ABILITY_LIGHTNING_ROD) { targetBattler ^= BIT_FLANK; RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); - gSpecialStatuses[targetBattler].lightningRodRedirected = 1; + gSpecialStatuses[targetBattler].lightningRodRedirected = TRUE; + } + else if (gMovesInfo[move].type == TYPE_WATER + && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_STORM_DRAIN) + && GetBattlerAbility(targetBattler) != ABILITY_STORM_DRAIN) + { + targetBattler ^= BIT_FLANK; + RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); + gSpecialStatuses[targetBattler].stormDrainRedirected = TRUE; } } break; @@ -6898,40 +6929,30 @@ u8 GetMoveTarget(u16 move, u8 setTarget) case MOVE_TARGET_BOTH: case MOVE_TARGET_FOES_AND_ALLY: case MOVE_TARGET_OPPONENTS_FIELD: - targetBattler = GetBattlerAtPosition((GetBattlerPosition(gBattlerAttacker) & BIT_SIDE) ^ BIT_SIDE); - if (gAbsentBattlerFlags & gBitTable[targetBattler]) + targetBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker))); + if (!IsBattlerAlive(targetBattler)) targetBattler ^= BIT_FLANK; break; case MOVE_TARGET_RANDOM: - side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; - if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) + side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker)); + if (IsAffectedByFollowMe(gBattlerAttacker, side, move)) targetBattler = gSideTimers[side].followmeTarget; else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM) - { - if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) - { - if (Random() & 1) - targetBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - else - targetBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); - } - else - { - if (Random() & 1) - targetBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - else - targetBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); - } - if (gAbsentBattlerFlags & gBitTable[targetBattler]) - targetBattler ^= BIT_FLANK; - } + targetBattler = SetRandomTarget(gBattlerAttacker); else - targetBattler = GetBattlerAtPosition((GetBattlerPosition(gBattlerAttacker) & BIT_SIDE) ^ BIT_SIDE); + targetBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker))); break; case MOVE_TARGET_USER_OR_SELECTED: case MOVE_TARGET_USER: + default: targetBattler = gBattlerAttacker; break; + case MOVE_TARGET_ALLY: + if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker))) + targetBattler = BATTLE_PARTNER(gBattlerAttacker); + else + targetBattler = gBattlerAttacker; + break; } *(gBattleStruct->moveTarget + gBattlerAttacker) = targetBattler; @@ -7202,6 +7223,11 @@ u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct Addi return secondaryEffectChance; } +bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect) +{ + return additionalEffect->chance == 0 || CalcSecondaryEffectChance(battler, battlerAbility, additionalEffect) >= 100; +} + bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect) { u32 i; @@ -9063,6 +9089,30 @@ s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, } } +bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect) +{ + u32 i; + for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + { + if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect + && gMovesInfo[move].additionalEffects[i].self == TRUE) + return TRUE; + } + return FALSE; +} + +bool32 MoveHasAdditionalEffectWithChance(u32 move, u32 moveEffect, u32 chance) +{ + u32 i; + for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + { + if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect + && gMovesInfo[move].additionalEffects[i].chance == chance) + return TRUE; + } + return FALSE; +} + bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument) { return (gMovesInfo[move].argument == argument) && MoveHasAdditionalEffectSelf(move, moveEffect); @@ -9345,6 +9395,14 @@ u8 IsMonDisobedient(void) } } +// for AI so that typeEffectivenessModifier, weather, abilities and holdEffects are calculated only once +s32 CalculateMoveDamageVars(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier, + u32 weather, bool32 isCrit, u32 holdEffectAtk, u32 holdEffectDef, u32 abilityAtk, u32 abilityDef) +{ + return DoMoveDamageCalcVars(move, battlerAtk, battlerDef, moveType, fixedBasePower, isCrit, FALSE, FALSE, + typeEffectivenessModifier, weather, holdEffectAtk, holdEffectDef, abilityAtk, abilityDef); +} + static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 moveType, u32 battlerDef, u32 defType, u32 battlerAtk, bool32 recordAbilities) { uq4_12_t mod = GetTypeModifier(moveType, defType); @@ -9506,16 +9564,25 @@ uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, return modifier; } -bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect) +uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef) { - u32 i; - for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + uq4_12_t modifier = UQ_4_12(1.0); + u8 moveType = gMovesInfo[move].type; + + if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) { - if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect - && gMovesInfo[move].additionalEffects[i].self == TRUE) - return TRUE; + MulByTypeEffectiveness(&modifier, move, moveType, 0, gSpeciesInfo[speciesDef].types[0], 0, FALSE); + if (gSpeciesInfo[speciesDef].types[1] != gSpeciesInfo[speciesDef].types[0]) + MulByTypeEffectiveness(&modifier, move, moveType, 0, gSpeciesInfo[speciesDef].types[1], 0, FALSE); + + if (moveType == TYPE_GROUND && abilityDef == ABILITY_LEVITATE && !(gFieldStatuses & STATUS_FIELD_GRAVITY)) + modifier = UQ_4_12(0.0); + if (abilityDef == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0) && gMovesInfo[move].power) + modifier = UQ_4_12(0.0); } - return FALSE; + + UpdateMoveResultFlags(modifier); + return modifier; } static uq4_12_t GetInverseTypeMultiplier(uq4_12_t multiplier) @@ -10441,120 +10508,120 @@ bool32 CanUltraBurst(u32 battler) // battle_ai_util.c -bool32 IsHealingMove(u32 move) -{ - return gMovesInfo[move].healingMove; -} +// bool32 IsHealingMove(u32 move) +// { +// return gMovesInfo[move].healingMove; +// } -void RecordKnownMove(u32 battlerId, u32 move) -{ - s32 i; - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (BATTLE_HISTORY->usedMoves[battlerId][i] == move) - break; - if (BATTLE_HISTORY->usedMoves[battlerId][i] == MOVE_NONE) - { - BATTLE_HISTORY->usedMoves[battlerId][i] = move; - // TODO: AI - // AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].moves[i] = move; - break; - } - } -} +// void RecordKnownMove(u32 battlerId, u32 move) +// { +// s32 i; +// for (i = 0; i < MAX_MON_MOVES; i++) +// { +// if (BATTLE_HISTORY->usedMoves[battlerId][i] == move) +// break; +// if (BATTLE_HISTORY->usedMoves[battlerId][i] == MOVE_NONE) +// { +// BATTLE_HISTORY->usedMoves[battlerId][i] = move; +// // TODO: AI +// // AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].moves[i] = move; +// break; +// } +// } +// } -s32 CountUsablePartyMons(u32 battlerId) -{ - s32 battlerOnField1, battlerOnField2, i, ret; - struct Pokemon *party; +// s32 CountUsablePartyMons(u32 battlerId) +// { +// s32 battlerOnField1, battlerOnField2, i, ret; +// struct Pokemon *party; - if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) - party = gPlayerParty; - else - party = gEnemyParty; +// if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) +// party = gPlayerParty; +// else +// party = gEnemyParty; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - battlerOnField1 = gBattlerPartyIndexes[battlerId]; - battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))]; - } - else // In singles there's only one battlerId by side. - { - battlerOnField1 = gBattlerPartyIndexes[battlerId]; - battlerOnField2 = gBattlerPartyIndexes[battlerId]; - } +// if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) +// { +// battlerOnField1 = gBattlerPartyIndexes[battlerId]; +// battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))]; +// } +// else // In singles there's only one battlerId by side. +// { +// battlerOnField1 = gBattlerPartyIndexes[battlerId]; +// battlerOnField2 = gBattlerPartyIndexes[battlerId]; +// } - ret = 0; - for (i = 0; i < PARTY_SIZE; i++) - { - if (i != battlerOnField1 && i != battlerOnField2 - && GetMonData(&party[i], MON_DATA_HP) != 0 - && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE - && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG) - { - ret++; - } - } +// ret = 0; +// for (i = 0; i < PARTY_SIZE; i++) +// { +// if (i != battlerOnField1 && i != battlerOnField2 +// && GetMonData(&party[i], MON_DATA_HP) != 0 +// && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE +// && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG) +// { +// ret++; +// } +// } - return ret; -} +// return ret; +// } -bool32 IsAiVsAiBattle(void) -{ - // TODO: Flag? - return (B_FLAG_AI_VS_AI_BATTLE && FlagGet(B_FLAG_AI_VS_AI_BATTLE)); -} +// bool32 IsAiVsAiBattle(void) +// { +// // TODO: Flag? +// return (B_FLAG_AI_VS_AI_BATTLE && FlagGet(B_FLAG_AI_VS_AI_BATTLE)); +// } -void RecordLastUsedMoveBy(u32 battlerId, u32 move) -{ - u8 *index = &BATTLE_HISTORY->moveHistoryIndex[battlerId]; +// void RecordLastUsedMoveBy(u32 battlerId, u32 move) +// { +// u8 *index = &BATTLE_HISTORY->moveHistoryIndex[battlerId]; - if (++(*index) >= AI_MOVE_HISTORY_COUNT) - *index = 0; - BATTLE_HISTORY->moveHistory[battlerId][*index] = move; -} +// if (++(*index) >= AI_MOVE_HISTORY_COUNT) +// *index = 0; +// BATTLE_HISTORY->moveHistory[battlerId][*index] = move; +// } -bool32 BattlerHasAi(u32 battlerId) -{ - switch (GetBattlerPosition(battlerId)) - { - case B_POSITION_PLAYER_LEFT: - if (IsAiVsAiBattle()) - return TRUE; - default: - return FALSE; - case B_POSITION_OPPONENT_LEFT: - return TRUE; - case B_POSITION_PLAYER_RIGHT: - if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) || IsAiVsAiBattle()) - return TRUE; - else - return FALSE; - case B_POSITION_OPPONENT_RIGHT: - return TRUE; - } -} +// bool32 BattlerHasAi(u32 battlerId) +// { +// switch (GetBattlerPosition(battlerId)) +// { +// case B_POSITION_PLAYER_LEFT: +// if (IsAiVsAiBattle()) +// return TRUE; +// default: +// return FALSE; +// case B_POSITION_OPPONENT_LEFT: +// return TRUE; +// case B_POSITION_PLAYER_RIGHT: +// if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) || IsAiVsAiBattle()) +// return TRUE; +// else +// return FALSE; +// case B_POSITION_OPPONENT_RIGHT: +// return TRUE; +// } +// } -void ClearBattlerItemEffectHistory(u32 battlerId) -{ - BATTLE_HISTORY->itemEffects[battlerId] = 0; -} +// void ClearBattlerItemEffectHistory(u32 battlerId) +// { +// BATTLE_HISTORY->itemEffects[battlerId] = 0; +// } -// move checks -bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect) -{ - if (ability == ABILITY_OVERCOAT - || (B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) - || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES) - return FALSE; - return TRUE; -} +// // move checks +// bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect) +// { +// if (ability == ABILITY_OVERCOAT +// || (B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) +// || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES) +// return FALSE; +// return TRUE; +// } -void RecordAllMoves(u32 battler) -{ - // TODO: AI - // memcpy(AI_PARTY->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]].moves, gBattleMons[battler].moves, MAX_MON_MOVES * sizeof(u16)); -} +// void RecordAllMoves(u32 battler) +// { +// // TODO: AI +// // memcpy(AI_PARTY->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]].moves, gBattleMons[battler].moves, MAX_MON_MOVES * sizeof(u16)); +// } // end battle_ai_util.c \ No newline at end of file diff --git a/src/data/trainer_parties.h b/src/data/trainer_parties.h index 275a02365..0bf93234d 100644 --- a/src/data/trainer_parties.h +++ b/src/data/trainer_parties.h @@ -9922,6 +9922,7 @@ static const struct TrainerMon sParty_TestBattle[] = { { .lvl = 14, .species = SPECIES_VENUSAUR, + .heldItem = ITEM_VENUSAURITE, }, { .lvl = 14, diff --git a/src/party_menu.c b/src/party_menu.c index 290560cff..bc2c3509c 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -1219,6 +1219,24 @@ static void HandleChooseMonSelection(u8 taskId, s8 *slotPtr) if (IsSelectedMonNotEgg((u8 *)slotPtr)) TryEnterMonForMinigame(taskId, (u8)*slotPtr); break; + case PARTY_ACTION_CHOOSE_FAINTED_MON: + { + u8 partyId = GetPartyIdFromBattleSlot((u8)*slotPtr); + if (GetMonData(&gPlayerParty[*slotPtr], MON_DATA_HP) > 0 + || GetMonData(&gPlayerParty[*slotPtr], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG + || ((gBattleTypeFlags & BATTLE_TYPE_MULTI) && partyId >= (PARTY_SIZE / 2))) + { + // Can't select if egg, alive, or doesn't belong to you + PlaySE(SE_FAILURE); + } + else + { + PlaySE(SE_SELECT); + gSelectedMonPartyId = partyId; + Task_ClosePartyMenu(taskId); + } + break; + } default: case PARTY_ACTION_ABILITY_PREVENTS: case PARTY_ACTION_SWITCHING: diff --git a/src/pokemon.c b/src/pokemon.c index 20d386311..0e227783c 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -3125,30 +3125,28 @@ static u8 CopyMonToPC(struct Pokemon *mon) return MON_CANT_GIVE; } -u8 CalculatePlayerPartyCount(void) +u8 CalculatePartyCount(struct Pokemon *party) { - gPlayerPartyCount = 0; + u32 partyCount = 0; - while (gPlayerPartyCount < PARTY_SIZE - && GetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + while (partyCount < PARTY_SIZE + && GetMonData(&party[partyCount], MON_DATA_SPECIES, NULL) != SPECIES_NONE) { - gPlayerPartyCount++; + partyCount++; } + return partyCount; +} + +u8 CalculatePlayerPartyCount(void) +{ + gPlayerPartyCount = CalculatePartyCount(gPlayerParty); return gPlayerPartyCount; } - u8 CalculateEnemyPartyCount(void) { - gEnemyPartyCount = 0; - - while (gEnemyPartyCount < PARTY_SIZE - && GetMonData(&gEnemyParty[gEnemyPartyCount], MON_DATA_SPECIES, NULL) != SPECIES_NONE) - { - gEnemyPartyCount++; - } - + gEnemyPartyCount = CalculatePartyCount(gEnemyParty); return gEnemyPartyCount; } @@ -3369,6 +3367,55 @@ void RemoveBattleMonPPBonus(struct BattlePokemon *mon, u8 moveIndex) mon->ppBonuses &= gPPUpClearMask[moveIndex]; } +void PokemonToBattleMon(struct Pokemon *src, struct BattlePokemon *dst) +{ + s32 i; + u8 nickname[POKEMON_NAME_BUFFER_SIZE]; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + dst->moves[i] = GetMonData(src, MON_DATA_MOVE1 + i, NULL); + dst->pp[i] = GetMonData(src, MON_DATA_PP1 + i, NULL); + } + + dst->species = GetMonData(src, MON_DATA_SPECIES, NULL); + dst->item = GetMonData(src, MON_DATA_HELD_ITEM, NULL); + dst->ppBonuses = GetMonData(src, MON_DATA_PP_BONUSES, NULL); + dst->friendship = GetMonData(src, MON_DATA_FRIENDSHIP, NULL); + dst->experience = GetMonData(src, MON_DATA_EXP, NULL); + dst->hpIV = GetMonData(src, MON_DATA_HP_IV, NULL); + dst->attackIV = GetMonData(src, MON_DATA_ATK_IV, NULL); + dst->defenseIV = GetMonData(src, MON_DATA_DEF_IV, NULL); + dst->speedIV = GetMonData(src, MON_DATA_SPEED_IV, NULL); + dst->spAttackIV = GetMonData(src, MON_DATA_SPATK_IV, NULL); + dst->spDefenseIV = GetMonData(src, MON_DATA_SPDEF_IV, NULL); + dst->personality = GetMonData(src, MON_DATA_PERSONALITY, NULL); + dst->status1 = GetMonData(src, MON_DATA_STATUS, NULL); + dst->level = GetMonData(src, MON_DATA_LEVEL, NULL); + dst->hp = GetMonData(src, MON_DATA_HP, NULL); + dst->maxHP = GetMonData(src, MON_DATA_MAX_HP, NULL); + dst->attack = GetMonData(src, MON_DATA_ATK, NULL); + dst->defense = GetMonData(src, MON_DATA_DEF, NULL); + dst->speed = GetMonData(src, MON_DATA_SPEED, NULL); + dst->spAttack = GetMonData(src, MON_DATA_SPATK, NULL); + dst->spDefense = GetMonData(src, MON_DATA_SPDEF, NULL); + dst->abilityNum = GetMonData(src, MON_DATA_ABILITY_NUM, NULL); + dst->otId = GetMonData(src, MON_DATA_OT_ID, NULL); + dst->type1 = gSpeciesInfo[dst->species].types[0]; + dst->type2 = gSpeciesInfo[dst->species].types[1]; + dst->type3 = TYPE_MYSTERY; + dst->ability = GetAbilityBySpecies(dst->species, dst->abilityNum); + GetMonData(src, MON_DATA_NICKNAME, nickname); + StringCopy_Nickname(dst->nickname, nickname); + GetMonData(src, MON_DATA_OT_NAME, dst->otName); + + for (i = 0; i < NUM_BATTLE_STATS; i++) + dst->statStages[i] = DEFAULT_STAT_STAGE; + + dst->status2 = 0; +} + + bool8 ExecuteTableBasedItemEffect(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex) { return PokemonUseItemEffects(mon, item, partyIndex, moveIndex, FALSE); @@ -5052,6 +5099,91 @@ bool8 TryIncrementMonLevel(struct Pokemon *mon) } } +static const u16 sUniversalMoves[] = +{ + MOVE_BIDE, + MOVE_FRUSTRATION, + MOVE_HIDDEN_POWER, + MOVE_MIMIC, + MOVE_NATURAL_GIFT, + MOVE_RAGE, + MOVE_RETURN, + MOVE_SECRET_POWER, + MOVE_SUBSTITUTE, + MOVE_TERA_BLAST, +}; + +u8 CanLearnTeachableMove(u16 species, u16 move) +{ + if (species == SPECIES_EGG) + { + return FALSE; + } + else if (species == SPECIES_MEW) + { + switch (move) + { + case MOVE_BADDY_BAD: + case MOVE_BOUNCY_BUBBLE: + case MOVE_BUZZY_BUZZ: + case MOVE_DRAGON_ASCENT: + case MOVE_FLOATY_FALL: + case MOVE_FREEZY_FROST: + case MOVE_GLITZY_GLOW: + case MOVE_RELIC_SONG: + case MOVE_SAPPY_SEED: + case MOVE_SECRET_SWORD: + case MOVE_SIZZLY_SLIDE: + case MOVE_SPARKLY_SWIRL: + case MOVE_SPLISHY_SPLASH: + case MOVE_VOLT_TACKLE: + case MOVE_ZIPPY_ZAP: + return FALSE; + default: + return TRUE; + } + } + else + { + u32 i, j; + const u16 *teachableLearnset = GetSpeciesTeachableLearnset(species); + for (i = 0; i < ARRAY_COUNT(sUniversalMoves); i++) + { + if (sUniversalMoves[i] == move) + { + if (!gSpeciesInfo[species].tmIlliterate) + { + if (move == MOVE_TERA_BLAST && GET_BASE_SPECIES_ID(species) == SPECIES_TERAPAGOS) + return FALSE; + if (GET_BASE_SPECIES_ID(species) == SPECIES_PYUKUMUKU && (move == MOVE_HIDDEN_POWER || move == MOVE_RETURN || move == MOVE_FRUSTRATION)) + return FALSE; + return TRUE; + } + else + { + const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species); + + if (P_TM_LITERACY < GEN_6) + return FALSE; + + for (j = 0; j < MAX_LEVEL_UP_MOVES && learnset[j].move != LEVEL_UP_MOVE_END; j++) + { + if (learnset[j].move == move) + return TRUE; + } + return FALSE; + } + } + } + for (i = 0; teachableLearnset[i] != MOVE_UNAVAILABLE; i++) + { + if (teachableLearnset[i] == move) + return TRUE; + } + return FALSE; + } +} + u32 CanMonLearnTMHM(struct Pokemon *mon, u8 tm) { u16 i; diff --git a/sym_ewram.txt b/sym_ewram.txt index 7e7fc424d..3eb4f08c7 100644 --- a/sym_ewram.txt +++ b/sym_ewram.txt @@ -62,7 +62,7 @@ .include "src/mail.o" .include "src/menu_helpers.o" .include "src/region_map.o" - .include "src/battle_ai_script_commands.o" + .include "src/battle_ai_main.o" .include "src/fldeff_rocksmash.o" .include "src/field_specials.o" .include "src/battle_records.o" From 7791678ba174746db3ca465952f75b5af9f1bf9d Mon Sep 17 00:00:00 2001 From: cawtds Date: Sat, 11 May 2024 13:37:46 +0200 Subject: [PATCH 03/11] fixed bug with AI switchout, removed unused functions, refactoring --- include/battle.h | 210 +++++----- include/battle_main.h | 1 - include/battle_script_commands.h | 3 - include/battle_util.h | 21 +- include/battle_util2.h | 1 + src/battle_ai_main.c | 3 - src/battle_bg.c | 12 +- src/battle_controller_oak_old_man.c | 2 +- src/battle_controller_opponent.c | 4 +- src/battle_controller_player.c | 2 +- src/battle_controller_pokedude.c | 2 +- src/battle_main.c | 469 +++-------------------- src/battle_message.c | 8 +- src/battle_script_commands.c | 153 -------- src/battle_util.c | 570 ++++++++++++++++++++-------- src/battle_util2.c | 27 +- src/party_menu.c | 2 +- src/quest_log_battle.c | 6 +- 18 files changed, 616 insertions(+), 880 deletions(-) diff --git a/include/battle.h b/include/battle.h index 247be3dd4..56061557a 100644 --- a/include/battle.h +++ b/include/battle.h @@ -553,167 +553,163 @@ struct BattleStruct { u8 turnEffectsTracker; u8 turnEffectsBattlerId; - u8 filler2; // unused u8 turnCountersTracker; u16 wrappedMove[MAX_BATTLERS_COUNT]; - u8 moveTarget[MAX_BATTLERS_COUNT]; + u16 moveTarget[MAX_BATTLERS_COUNT]; + u32 expShareExpValue; + u32 expValue; + u8 expGettersOrder[PARTY_SIZE]; // First battlers which were sent out, then via exp-share u8 expGetterMonId; - u8 field_11; // unused + u8 expOrderId:3; + u8 expGetterBattlerId:2; + u8 teamGotExpMsgPrinted:1; // The 'Rest of your team got msg' has been printed. + u8 givenExpMons; // Bits for enemy party's pokemon that gave exp to player's party. + u8 expSentInMons; // As bits for player party mons - not including exp share mons. u8 wildVictorySong; u8 dynamicMoveType; u8 wrappedBy[MAX_BATTLERS_COUNT]; - u8 focusPunchBattlerId; + u8 focusPunchBattlers; // as bits u8 battlerPreventingSwitchout; - u8 moneyMultiplier; + u8 moneyMultiplier:6; + u8 moneyMultiplierItem:1; + u8 moneyMultiplierMove:1; u8 savedTurnActionNumber; u8 switchInAbilitiesCounter; u8 faintedActionsState; u8 faintedActionsBattlerId; - // balign 2 - u32 expValue; u8 scriptPartyIdx; // for printing the nickname - u8 sentInPokes; bool8 selectionScriptFinished[MAX_BATTLERS_COUNT]; u8 battlerPartyIndexes[MAX_BATTLERS_COUNT]; u8 monToSwitchIntoId[MAX_BATTLERS_COUNT]; - u8 battlerPartyOrders[MAX_BATTLERS_COUNT][3]; + u8 battlerPartyOrders[MAX_BATTLERS_COUNT][PARTY_SIZE / 2]; u8 runTries; u8 caughtMonNick[POKEMON_NAME_LENGTH + 1]; - u8 field_78; // unused u8 safariRockThrowCounter; // safariGoNearCounter in pokeemerald u8 safariBaitThrowCounter; // safariPkblThrowCounter in pokeemerald u8 safariEscapeFactor; u8 safariCatchFactor; - u8 linkBattleVsSpriteId_V; - u8 linkBattleVsSpriteId_S; + u8 linkBattleVsSpriteId_V; // The letter "V" + u8 linkBattleVsSpriteId_S; // The letter "S" u8 formToChangeInto; u8 chosenMovePositions[MAX_BATTLERS_COUNT]; u8 stateIdAfterSelScript[MAX_BATTLERS_COUNT]; - u8 field_88; // unused - u8 field_89; // unused - u8 field_8A; // unused - u8 playerPartyIdx; - u8 field_8C; // unused - u8 field_8D; // unused + u8 prevSelectedPartySlot; u8 stringMoveType; - u8 expGetterBattlerId; - u8 field_90; // unused u8 absentBattlerFlags; - u8 AI_monToSwitchIntoId[2]; - u8 simulatedInputState[4]; // used by Oak/Old Man/Pokedude controllers - u8 lastTakenMove[MAX_BATTLERS_COUNT * 2 * 2]; // ask gamefreak why they declared it that way - u16 hpOnSwitchout[2]; + u8 field_93; // related to choosing pokemon? + u8 simulatedInputState[4]; // used by Oak/Old Man/Pokedude controllers, Wally States/Frames in pokeemerald + u16 lastTakenMove[MAX_BATTLERS_COUNT]; // Last move that a battler was hit with. + u16 hpOnSwitchout[NUM_BATTLE_SIDES]; + u32 savedBattleTypeFlags; u16 abilityPreventingSwitchout; u8 hpScale; - u16 savedBattleTypeFlags; - void (*savedCallback)(void); u16 synchronizeMoveEffect; - u8 multiplayerId; - u8 overworldWeatherDone; - u8 atkCancellerTracker; + bool8 anyMonHasTransformed; + void (*savedCallback)(void); u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle - u8 chosenItem[MAX_BATTLERS_COUNT]; // why is this an u8? - u8 AI_itemType[2]; - u8 AI_itemFlags[2]; + u16 chosenItem[MAX_BATTLERS_COUNT]; u16 choicedMove[MAX_BATTLERS_COUNT]; u16 changedItems[MAX_BATTLERS_COUNT]; - u8 intimidateBattler; u8 switchInItemsCounter; - u8 field_DA; // battle tower related u8 turnSideTracker; - u8 fillerDC[0xDF-0xDC]; - u8 givenExpMons; - u8 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; - u8 wishPerishSongState; - u8 wishPerishSongBattlerId; - u8 lastAttackerToFaintOpponent; - // align 4 + u16 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; // a 2-D array [target][attacker] union { struct LinkBattlerHeader linkBattlerHeader; struct MultiPartnerMenuPokemon multiBattleMons[3]; } multiBuffer; - u8 itemPartyIndex[MAX_BATTLERS_COUNT]; - u8 itemMoveIndex[MAX_BATTLERS_COUNT]; - u8 padding_1E4[0x14]; - // pokeemerald - u8 isSkyBattle:1; + u8 wishPerishSongState; + u8 wishPerishSongBattlerId; + u8 overworldWeatherDone:1; + u8 startingStatusDone:1; u8 isAtkCancelerForCalledMove:1; // Certain cases in atk canceler should only be checked once, when the original move is called, however others need to be checked the twice. - u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky - u8 beatUpSlot:3; - u8 pledgeMove:1; + u8 terrainDone:1; + u8 startingStatus; // status to apply at battle start. defined in constants/battle.h + u8 startingStatusTimer; + u8 atkCancellerTracker; + u8 AI_monToSwitchIntoId[MAX_BATTLERS_COUNT]; + u8 alreadyStatusedMoveAttempt; // As bits for battlers; For example when using Thunder Wave on an already paralyzed Pokémon. u8 magnitudeBasePower; u8 presentBasePower; - u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used. - u8 lastMoveFailed; // as bits for each battler, for the sake of Stomping Tantrum - bool8 ateBoost[MAX_BATTLERS_COUNT]; - u8 timesGotHit[NUM_BATTLE_SIDES][PARTY_SIZE]; - u8 supremeOverlordCounter[MAX_BATTLERS_COUNT]; - struct Illusion illusion[MAX_BATTLERS_COUNT]; - u8 trainerSlideFirstSTABMoveMsgState:2; - u8 blunderPolicy:1; // should blunder policy activate - u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle. - u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies. - u8 enduredDamage; - u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon. - u8 trainerSlideFirstCriticalHitMsgState:2; - u8 trainerSlideFirstSuperEffectiveHitMsgState:2; - u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects - u8 targetsDone[MAX_BATTLERS_COUNT]; // Each battler as a bit. - u16 moveEffect2; // For Knock Off - u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages - u8 stickySyrupdBy[MAX_BATTLERS_COUNT]; - u8 moneyMultiplierMove:1; - struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member) + u8 roostTypes[MAX_BATTLERS_COUNT][2]; u8 savedBattlerTarget; - u8 ateBerry[2]; // array id determined by side, each party pokemon as bit - u16 overwrittenAbilities[MAX_BATTLERS_COUNT]; // abilities overwritten during battle (keep separate from battle history in case of switching) + bool8 ateBoost[MAX_BATTLERS_COUNT]; + u8 activeAbilityPopUps; // as bits for each battler + u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler + bool8 throwingPokeBall; struct MegaEvolutionData mega; struct UltraBurstData burst; struct ZMoveData zmove; struct DynamaxData dynamax; - u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change - bool8 allowedToChangeFormInWeather[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side, used by Ice Face. - u8 startingStatus; // status to apply at battle start. defined in constants/battle.h - u8 startingStatusTimer; - u8 transformZeroToHero[NUM_BATTLE_SIDES]; - u8 supersweetSyrup[NUM_BATTLE_SIDES]; - u8 intrepidSwordBoost[NUM_BATTLE_SIDES]; - u8 dauntlessShieldBoost[NUM_BATTLE_SIDES]; + const u8 *trainerSlideMsg; + bool8 trainerSlideLowHpMsgDone; + u8 introState; + u8 ateBerry[2]; // array id determined by side, each party pokemon as bit + u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages + u8 lastMoveFailed; // as bits for each battler, for the sake of Stomping Tantrum + u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct u16 tracedAbility[MAX_BATTLERS_COUNT]; u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk and Anger Shell. - u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles. - bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once. bool8 spriteIgnore0Hp; - u8 moneyMultiplierItem:1; - u8 expGettersOrder[PARTY_SIZE]; // First battlers which were sent out, then via exp-share - u32 expShareExpValue; - u8 expOrderId:3; - u8 expSentInMons; // As bits for player party mons - not including exp share mons. - u8 teamGotExpMsgPrinted:1; // The 'Rest of your team got msg' has been printed. - u8 roostTypes[MAX_BATTLERS_COUNT][2]; - u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct - u8 attackerBeforeBounce:2; - bool8 hitSwitchTargetFailed:1; - u8 storedHealingWish:4; // Each battler as a bit. - u8 storedLunarDance:4; // Each battler as a bit. - u8 forcedSwitch:4; // For each battler - u8 alreadyStatusedMoveAttempt; // As bits for battlers; For example when using Thunder Wave on an already paralyzed Pokémon. - u8 soulheartBattlerId; - const u8 *trainerSlideMsg; - u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party. - u8 quickClawBattlerId; - bool8 effectsBeforeUsingMoveDone:1; // Mega Evo and Focus Punch/Shell Trap effects. - u8 focusPunchBattlers; // as bits - u8 quickClawRandom[MAX_BATTLERS_COUNT]; - u8 quickDrawRandom[MAX_BATTLERS_COUNT]; - bool8 throwingPokeBall; + struct Illusion illusion[MAX_BATTLERS_COUNT]; s32 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier u8 aiMoveOrAction[MAX_BATTLERS_COUNT]; u8 aiChosenTarget[MAX_BATTLERS_COUNT]; + u8 soulheartBattlerId; + u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles. + bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once. + u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used. + u16 moveEffect2; // For Knock Off + u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon. + u8 quickClawBattlerId; + struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member) + u8 forcedSwitch:4; // For each battler + u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects + u8 blunderPolicy:1; // should blunder policy activate + u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky + u8 bouncedMoveIsUsed:1; + u8 ballSpriteIds[2]; // item gfx, window gfx + u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change + u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle. + // When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without. + u8 attackerBeforeBounce:2; + u8 beatUpSlot:3; + bool8 hitSwitchTargetFailed:1; + bool8 effectsBeforeUsingMoveDone:1; // Mega Evo and Focus Punch/Shell Trap effects. + u8 targetsDone[MAX_BATTLERS_COUNT]; // Each battler as a bit. + u16 overwrittenAbilities[MAX_BATTLERS_COUNT]; // abilities overwritten during battle (keep separate from battle history in case of switching) + bool8 allowedToChangeFormInWeather[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side, used by Ice Face. + u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party. + u8 storedHealingWish:4; // Each battler as a bit. + u8 storedLunarDance:4; // Each battler as a bit. + u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies. + u8 itemPartyIndex[MAX_BATTLERS_COUNT]; + u8 itemMoveIndex[MAX_BATTLERS_COUNT]; + u8 trainerSlideFirstCriticalHitMsgState:2; + u8 trainerSlideFirstSuperEffectiveHitMsgState:2; + u8 trainerSlideFirstSTABMoveMsgState:2; + u8 trainerSlidePlayerMonUnaffectedMsgState:2; + u8 trainerSlideHalfHpMsgDone:1; + u8 trainerSlideMegaEvolutionMsgDone:1; + u8 trainerSlideZMoveMsgDone:1; + u8 trainerSlideBeforeFirstTurnMsgDone:1; + u8 trainerSlideDynamaxMsgDone:1; + u8 pledgeMove:1; + u8 isSkyBattle:1; u32 aiDelayTimer; // Counts number of frames AI takes to choose an action. u32 aiDelayFrames; // Number of frames it took to choose an action. - // pokeemerald unknown use - u8 field_93; // related to choosing pokemon? probably related to recording + u8 timesGotHit[NUM_BATTLE_SIDES][PARTY_SIZE]; + u8 enduredDamage; + u8 transformZeroToHero[NUM_BATTLE_SIDES]; + u8 stickySyrupdBy[MAX_BATTLERS_COUNT]; + u8 intrepidSwordBoost[NUM_BATTLE_SIDES]; + u8 dauntlessShieldBoost[NUM_BATTLE_SIDES]; + u8 supersweetSyrup[NUM_BATTLE_SIDES]; + u8 supremeOverlordCounter[MAX_BATTLERS_COUNT]; + u8 quickClawRandom[MAX_BATTLERS_COUNT]; + u8 quickDrawRandom[MAX_BATTLERS_COUNT]; + // pokefirered + u8 field_DA; // battle tower related + u8 lastAttackerToFaintOpponent; }; extern struct BattleStruct *gBattleStruct; diff --git a/include/battle_main.h b/include/battle_main.h index 44f305920..f0b44bed0 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -86,7 +86,6 @@ void SwitchPartyOrder(u32 battlerId); void SwapTurnOrder(u8 id1, u8 id2); void RunBattleScriptCommands_PopCallbacksStack(void); void RunBattleScriptCommands(void); -bool8 TryRunFromBattle(u8 battler); s8 GetMovePriority(u32 battlerId, u16 move); s8 GetChosenMovePriority(u32 battlerId); u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect); diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 96ae0a6c7..b972039f3 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -22,9 +22,6 @@ struct PickupItem u8 percentage[10]; }; -void AI_CalcDmg(u8 attacker, u8 defender); -u8 TypeCalc(u16 move, u8 attacker, u8 defender); -u8 AI_TypeCalc(u16 move, u16 targetSpecies, u16 targetAbility); u8 GetBattlerTurnOrderNum(u8 battlerId); void SetMoveEffect(bool32 primary, u32 certain); bool32 IsMonGettingExpSentOut(void); diff --git a/include/battle_util.h b/include/battle_util.h index 415af1090..bb18ee01f 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -120,6 +120,12 @@ enum extern const struct TypePower gNaturalGiftTable[]; extern const uq4_12_t gTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES]; +void HandleAction_UseMove(void); +void HandleAction_Switch(void); +void HandleAction_UseItem(void); +bool8 TryRunFromBattle(u8 battler); +void HandleAction_Run(void); + u8 GetBattlerForBattleScript(u8 caseId); void MarkBattlerForControllerExec(u8 battlerId); void MarkBattlerReceivedLinkData(u8 battlerId); @@ -150,7 +156,6 @@ void ClearVariousBattlerFlags(u32 battler); void HandleAction_RunBattleScript(void); u32 GetMoveTarget(u16 move, u8 setTarget); u8 IsMonDisobedient(void); -void SwitchPartyOrderInGameMulti(u8 battler, u8 arg1); // new bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move); bool32 IsNeutralizingGasOnField(void); @@ -254,18 +259,4 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter); s32 CalculateMoveDamageVars(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier, u32 weather, bool32 isCrit, u32 holdEffectAtk, u32 holdEffectDef, u32 abilityAtk, u32 abilityDef); - -// battle_ai_util.h -// bool32 IsHealingMove(u32 move); -// void RecordKnownMove(u32 battlerId, u32 move); -// s32 CountUsablePartyMons(u32 battlerId); -// bool32 IsAiVsAiBattle(void); -// void RecordLastUsedMoveBy(u32 battlerId, u32 move); -// bool32 BattlerHasAi(u32 battlerId); -// void ClearBattlerItemEffectHistory(u32 battlerId); -// bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect); -// void RecordAllMoves(u32 battler); - -// end battle_ai_util.h - #endif // GUARD_BATTLE_UTIL_H diff --git a/include/battle_util2.h b/include/battle_util2.h index 8ca726856..91072d3bc 100644 --- a/include/battle_util2.h +++ b/include/battle_util2.h @@ -6,5 +6,6 @@ void AllocateBattleResources(void); void FreeBattleResources(void); void AdjustFriendshipOnBattleFaint(u8 bank); +void SwitchPartyOrderInGameMulti(u8 battler, u8 arg1); #endif // GUARD_BATTLE_UTIL_H diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 2d1a4f558..a15bd3061 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -268,9 +268,6 @@ u32 BattleAI_ChooseMoveOrAction(void) // Clear protect structures, some flags may be set during AI calcs // e.g. pranksterElevated from GetMovePriority memset(&gProtectStructs, 0, MAX_BATTLERS_COUNT * sizeof(struct ProtectStruct)); - #if TESTING - TestRunner_Battle_CheckAiMoveScores(sBattler_AI); - #endif // TESTING return ret; } diff --git a/src/battle_bg.c b/src/battle_bg.c index 3bcc50080..ad3fa73b9 100644 --- a/src/battle_bg.c +++ b/src/battle_bg.c @@ -777,7 +777,7 @@ static void DrawLinkBattleParticipantPokeballs(u8 taskId, u8 multiplayerId, u8 b } else { - if (multiplayerId == gBattleStruct->multiplayerId) + if (multiplayerId == gBattleScripting.multiplayerId) pokeballStatuses = gTasks[taskId].data[3]; else pokeballStatuses = gTasks[taskId].data[4]; @@ -800,7 +800,7 @@ static void DrawLinkBattleVsScreenOutcomeText(void) { if (gBattleOutcome == B_OUTCOME_WON) { - switch (gLinkPlayers[gBattleStruct->multiplayerId].id) + switch (gLinkPlayers[gBattleScripting.multiplayerId].id) { case 0: BattlePutTextOnWindow(gText_Win, B_WIN_VS_OUTCOME_LEFT); @@ -822,7 +822,7 @@ static void DrawLinkBattleVsScreenOutcomeText(void) } else { - switch (gLinkPlayers[gBattleStruct->multiplayerId].id) + switch (gLinkPlayers[gBattleScripting.multiplayerId].id) { case 0: BattlePutTextOnWindow(gText_Win, B_WIN_VS_OUTCOME_RIGHT); @@ -845,7 +845,7 @@ static void DrawLinkBattleVsScreenOutcomeText(void) } else if (gBattleOutcome == B_OUTCOME_WON) { - if (gLinkPlayers[gBattleStruct->multiplayerId].id != 0) + if (gLinkPlayers[gBattleScripting.multiplayerId].id != 0) { BattlePutTextOnWindow(gText_Win, B_WIN_VS_OUTCOME_RIGHT); BattlePutTextOnWindow(gText_Loss, B_WIN_VS_OUTCOME_LEFT); @@ -858,7 +858,7 @@ static void DrawLinkBattleVsScreenOutcomeText(void) } else { - if (gLinkPlayers[gBattleStruct->multiplayerId].id != 0) + if (gLinkPlayers[gBattleScripting.multiplayerId].id != 0) { BattlePutTextOnWindow(gText_Win, B_WIN_VS_OUTCOME_LEFT); BattlePutTextOnWindow(gText_Loss, B_WIN_VS_OUTCOME_RIGHT); @@ -910,7 +910,7 @@ void InitLinkBattleVsScreen(u8 taskId) } else { - u8 playerId = gBattleStruct->multiplayerId; + u8 playerId = gBattleScripting.multiplayerId; u8 opponentId = playerId ^ BIT_SIDE; u8 opponentId_copy = opponentId; diff --git a/src/battle_controller_oak_old_man.c b/src/battle_controller_oak_old_man.c index 8a1478522..2a522b1fc 100644 --- a/src/battle_controller_oak_old_man.c +++ b/src/battle_controller_oak_old_man.c @@ -838,7 +838,7 @@ static void OakOldManHandleChoosePokemon(u32 battler) gBattleControllerData[battler] = CreateTask(TaskDummy, 0xFF); gTasks[gBattleControllerData[battler]].data[0] = gBattleResources->bufferA[battler][1] & 0xF; *(&gBattleStruct->battlerPreventingSwitchout) = gBattleResources->bufferA[battler][1] >> 4; - *(&gBattleStruct->playerPartyIdx) = gBattleResources->bufferA[battler][2]; + *(&gBattleStruct->prevSelectedPartySlot) = gBattleResources->bufferA[battler][2]; *(&gBattleStruct->abilityPreventingSwitchout) = (gBattleResources->bufferA[battler][3] & 0xFF) | (gBattleResources->bufferA[battler][7] << 8); for (i = 0; i < 3; ++i) gBattlePartyCurrentOrder[i] = gBattleResources->bufferA[battler][4 + i]; diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 8d0c345cc..39714e25c 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -66,9 +66,9 @@ static void (*const sOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) [CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty, // done [CONTROLLER_CHOOSEACTION] = OpponentHandleChooseAction, // done [CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty, // done - [CONTROLLER_CHOOSEMOVE] = OpponentHandleChooseMove, // done TODO: AI refactoring + [CONTROLLER_CHOOSEMOVE] = OpponentHandleChooseMove, // done [CONTROLLER_OPENBAG] = OpponentHandleChooseItem, // done - [CONTROLLER_CHOOSEPOKEMON] = OpponentHandleChoosePokemon, // done TODO: AI refactoring + [CONTROLLER_CHOOSEPOKEMON] = OpponentHandleChoosePokemon, // done [CONTROLLER_23] = BtlController_Empty, // done [CONTROLLER_HEALTHBARUPDATE] = OpponentHandleHealthBarUpdate, // done [CONTROLLER_EXPUPDATE] = BtlController_Empty, // done diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 945acd081..ed812768d 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -1783,7 +1783,7 @@ static void PlayerHandleChoosePokemon(u32 battler) gBattleControllerData[battler] = CreateTask(TaskDummy, 0xFF); gTasks[gBattleControllerData[battler]].data[0] = gBattleResources->bufferA[battler][1] & 0xF; *(&gBattleStruct->battlerPreventingSwitchout) = gBattleResources->bufferA[battler][1] >> 4; - *(&gBattleStruct->playerPartyIdx) = gBattleResources->bufferA[battler][2]; + *(&gBattleStruct->prevSelectedPartySlot) = gBattleResources->bufferA[battler][2]; *(&gBattleStruct->abilityPreventingSwitchout) = (gBattleResources->bufferA[battler][3] & 0xFF) | (gBattleResources->bufferA[battler][7] << 8); BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); gBattlerControllerFuncs[battler] = OpenPartyMenuToChooseMon; diff --git a/src/battle_controller_pokedude.c b/src/battle_controller_pokedude.c index 082702396..9643ad76a 100644 --- a/src/battle_controller_pokedude.c +++ b/src/battle_controller_pokedude.c @@ -735,7 +735,7 @@ static void PokedudeHandleChoosePokemon(u32 battler) gBattleControllerData[battler] = CreateTask(TaskDummy, 0xFF); gTasks[gBattleControllerData[battler]].data[0] = gBattleResources->bufferA[battler][1] & 0xF; *(&gBattleStruct->battlerPreventingSwitchout) = gBattleResources->bufferA[battler][1] >> 4; - *(&gBattleStruct->playerPartyIdx) = gBattleResources->bufferA[battler][2]; + *(&gBattleStruct->prevSelectedPartySlot) = gBattleResources->bufferA[battler][2]; *(&gBattleStruct->abilityPreventingSwitchout) = (gBattleResources->bufferA[battler][3] & 0xFF) | (gBattleResources->bufferA[battler][7] << 8); for (i = 0; i < 3; ++i) gBattlePartyCurrentOrder[i] = gBattleResources->bufferA[battler][4 + i]; diff --git a/src/battle_main.c b/src/battle_main.c index 6dd00222e..71b7c0671 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -45,10 +45,6 @@ #include "constants/trainers.h" static void SpriteCB_UnusedDebugSprite(struct Sprite *sprite); -static void HandleAction_UseMove(void); -static void HandleAction_Switch(void); -static void HandleAction_UseItem(void); -static void HandleAction_Run(void); static void HandleAction_WatchesCarefully(void); static void HandleAction_SafariZoneBallThrow(void); static void HandleAction_ThrowBait(void); @@ -1221,7 +1217,7 @@ static void CB2_HandleStartBattle(void) AnimateSprites(); BuildOamBuffer(); playerMultiplayerId = GetMultiplayerId(); - gBattleStruct->multiplayerId = playerMultiplayerId; + gBattleScripting.multiplayerId = playerMultiplayerId; enemyMultiplayerId = playerMultiplayerId ^ BIT_SIDE; switch (gBattleCommunication[MULTIUSE_STATE]) { @@ -1399,11 +1395,11 @@ static void CB2_PreInitMultiBattle(void) s32 i; u8 playerMultiplierId; u8 r4 = 0xF; - u16 *savedBattleTypeFlags; + u32 *savedBattleTypeFlags; void (**savedCallback)(void); playerMultiplierId = GetMultiplayerId(); - gBattleStruct->multiplayerId = playerMultiplierId; + gBattleScripting.multiplayerId = playerMultiplierId; savedCallback = &gBattleStruct->savedCallback; savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags; @@ -1512,7 +1508,7 @@ static void CB2_HandleStartMultiBattle(void) u8 taskId; playerMultiplayerId = GetMultiplayerId(); - gBattleStruct->multiplayerId = playerMultiplayerId; + gBattleScripting.multiplayerId = playerMultiplayerId; RunTasks(); AnimateSprites(); BuildOamBuffer(); @@ -2110,7 +2106,7 @@ static void BufferPartyVsScreenHealth_AtEnd(u8 taskId) { struct Pokemon *party1 = NULL; struct Pokemon *party2 = NULL; - u8 multiplayerId = gBattleStruct->multiplayerId; + u8 multiplayerId = gBattleScripting.multiplayerId; u32 flags; s32 i; @@ -2862,8 +2858,7 @@ void SwitchInClearSetData(u32 battler) // Clear selected party ID so Revival Blessing doesn't get confused. gSelectedMonPartyId = PARTY_SIZE; - // TODO: AI - // Ai_UpdateSwitchInData(battler); + Ai_UpdateSwitchInData(battler); } const u8* FaintClearSetData(u32 battler) @@ -3565,6 +3560,7 @@ void SwitchPartyOrder(u32 battler) enum { + STATE_TURN_START_RECORD, STATE_BEFORE_ACTION_CHOSEN, STATE_WAIT_ACTION_CHOSEN, STATE_WAIT_ACTION_CASE_CHOSEN, @@ -3585,6 +3581,16 @@ static void HandleTurnActionSelectionState(void) u32 position = GetBattlerPosition(battler); switch (gBattleCommunication[battler]) { + case STATE_TURN_START_RECORD: // Recorded battle related action on start of every turn. + gBattleCommunication[battler] = STATE_BEFORE_ACTION_CHOSEN; + + // Do AI score computations here so we can use them in AI_TrySwitchOrUseItem + if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart()) && BattlerHasAi(battler)) + { + AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, FALSE); + gBattleStruct->aiMoveOrAction[battler] = ComputeBattleAiScores(battler); + } + // fallthrough case STATE_BEFORE_ACTION_CHOSEN: // Choose an action. *(gBattleStruct->monToSwitchIntoId + battler) = PARTY_SIZE; if (gBattleTypeFlags & BATTLE_TYPE_MULTI @@ -3631,6 +3637,7 @@ static void HandleTurnActionSelectionState(void) if (!(gBattleControllerExecFlags & ((gBitTable[battler]) | (0xF << 28) | (gBitTable[battler] << 4) | (gBitTable[battler] << 8) | (gBitTable[battler] << 12)))) { gChosenActionByBattler[battler] = gBattleResources->bufferB[battler][1]; + switch (gBattleResources->bufferB[battler][1]) { case B_ACTION_USE_MOVE: @@ -3659,13 +3666,15 @@ static void HandleTurnActionSelectionState(void) moveInfo.monType1 = gBattleMons[battler].type1; moveInfo.monType2 = gBattleMons[battler].type2; moveInfo.monType3 = gBattleMons[battler].type3; + for (i = 0; i < MAX_MON_MOVES; i++) { moveInfo.moves[i] = gBattleMons[battler].moves[i]; moveInfo.currentPp[i] = gBattleMons[battler].pp[i]; - moveInfo.maxPp[i] = CalculatePPWithBonus(gBattleMons[battler].moves[i], - gBattleMons[battler].ppBonuses, - i); + moveInfo.maxPp[i] = CalculatePPWithBonus( + gBattleMons[battler].moves[i], + gBattleMons[battler].ppBonuses, + i); } BtlController_EmitChooseMove(battler, BUFFER_A, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0, FALSE, &moveInfo); @@ -3673,7 +3682,20 @@ static void HandleTurnActionSelectionState(void) } break; case B_ACTION_USE_ITEM: - if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER) || gStatuses3[battler] & STATUS3_SKY_DROPPED) + if (FlagGet(B_FLAG_NO_BAG_USE)) + { + gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed; + gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; + *(gBattleStruct->selectionScriptFinished + battler) = FALSE; + *(gBattleStruct->stateIdAfterSelScript + battler) = STATE_BEFORE_ACTION_CHOSEN; + return; + } + + if ((gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_BATTLE_TOWER + | BATTLE_TYPE_EREADER_TRAINER)) + // Or if currently held by Sky Drop + || gStatuses3[battler] & STATUS3_SKY_DROPPED) { gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; @@ -3694,7 +3716,7 @@ static void HandleTurnActionSelectionState(void) BtlController_EmitChoosePokemon(battler, BUFFER_A, PARTY_ACTION_CANT_SWITCH, PARTY_SIZE, ABILITY_NONE, gBattleStruct->battlerPartyOrders[battler]); } else if (ItemId_GetHoldEffect(gBattleMons[battler].item) != HOLD_EFFECT_SHED_SHELL - && (i = IsAbilityPreventingEscape(battler))) + && (i = IsAbilityPreventingEscape(battler))) // must be last to keep i value integrity { BtlController_EmitChoosePokemon(battler, BUFFER_A, ((i - 1) << 4) | PARTY_ACTION_ABILITY_PREVENTS, PARTY_SIZE, gBattleMons[i - 1].ability, gBattleStruct->battlerPartyOrders[battler]); } @@ -3735,7 +3757,7 @@ static void HandleTurnActionSelectionState(void) gBattleStruct->dynamax.toDynamax &= ~(gBitTable[BATTLE_PARTNER(GetBattlerPosition(battler))]); gBattleStruct->dynamax.usingMaxMove[BATTLE_PARTNER(GetBattlerPosition(battler))] = FALSE; gBattleStruct->zmove.toBeUsed[BATTLE_PARTNER(GetBattlerPosition(battler))] = MOVE_NONE; - BtlController_EmitEndBounceEffect(battler, 0); + BtlController_EmitEndBounceEffect(battler, BUFFER_A); MarkBattlerForControllerExec(battler); return; } @@ -3799,10 +3821,10 @@ static void HandleTurnActionSelectionState(void) else { // Get the chosen move position (and thus the chosen move) and target from the returned buffer. - *(gBattleStruct->chosenMovePositions + battler) = gBattleResources->bufferB[battler][2] & ~(RET_MEGA_EVOLUTION | RET_ULTRA_BURST | RET_DYNAMAX); + gBattleStruct->chosenMovePositions[battler] = gBattleResources->bufferB[battler][2] & ~(RET_MEGA_EVOLUTION | RET_ULTRA_BURST | RET_DYNAMAX); gChosenMoveByBattler[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; - *(gBattleStruct->moveTarget + battler) = gBattleResources->bufferB[battler][3]; - + gBattleStruct->moveTarget[battler] = gBattleResources->bufferB[battler][3]; + // Check to see if any gimmicks need to be prepared. if (gBattleResources->bufferB[battler][2] & RET_MEGA_EVOLUTION) gBattleStruct->mega.toEvolve |= gBitTable[battler]; @@ -3832,6 +3854,8 @@ static void HandleTurnActionSelectionState(void) else { gLastUsedItem = (gBattleResources->bufferB[battler][1] | (gBattleResources->bufferB[battler][2] << 8)); + if (ItemId_GetPocket(gLastUsedItem) == POCKET_POKE_BALLS) + gBattleStruct->throwingPokeBall = TRUE; gBattleCommunication[battler]++; } break; @@ -3842,16 +3866,7 @@ static void HandleTurnActionSelectionState(void) } else { - *(gBattleStruct->monToSwitchIntoId + battler) = gBattleResources->bufferB[battler][1]; - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - { - *(battler * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 0) &= 0xF; - *(battler * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 0) |= (gBattleResources->bufferB[battler][2] & 0xF0); - *(battler * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 1) = gBattleResources->bufferB[battler][3]; - *(BATTLE_PARTNER(battler) * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 0) &= (0xF0); - *(BATTLE_PARTNER(battler) * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 0) |= (gBattleResources->bufferB[battler][2] & 0xF0) >> 4; - *(BATTLE_PARTNER(battler) * 3 + (u8 *)(gBattleStruct->battlerPartyOrders) + 2) = gBattleResources->bufferB[battler][3]; - } + UpdateBattlerPartyOrdersOnSwitch(battler); gBattleCommunication[battler]++; } break; @@ -4712,400 +4727,6 @@ void RunBattleScriptCommands(void) gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); } -// Functions -void HandleAction_UseMove(void) -{ - u32 battler, i, side, moveType, var = 4; - u16 moveTarget; - - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - if (gBattleStruct->absentBattlerFlags & gBitTable[gBattlerAttacker] || !IsBattlerAlive(gBattlerAttacker)) - { - gCurrentActionFuncId = B_ACTION_FINISHED; - return; - } - - gIsCriticalHit = FALSE; - gBattleStruct->atkCancellerTracker = 0; - gMoveResultFlags = 0; - gMultiHitCounter = 0; - gBattleScripting.savedDmg = 0; - gBattleCommunication[MISS_TYPE] = 0; - gBattleScripting.savedMoveEffect = 0; - gCurrMovePos = gChosenMovePos = *(gBattleStruct->chosenMovePositions + gBattlerAttacker); - - // choose move - if (gProtectStructs[gBattlerAttacker].noValidMoves) - { - gProtectStructs[gBattlerAttacker].noValidMoves = FALSE; - gCurrentMove = gChosenMove = MOVE_STRUGGLE; - gHitMarker |= HITMARKER_NO_PPDEDUCT; - *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(MOVE_STRUGGLE, NO_TARGET_OVERRIDE); - } - else if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS || gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) - { - gCurrentMove = gChosenMove = gLockedMoves[gBattlerAttacker]; - } - // encore forces you to use the same move - else if (!gBattleStruct->zmove.active && gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE - && gDisableStructs[gBattlerAttacker].encoredMove == gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos]) - { - gCurrentMove = gChosenMove = gDisableStructs[gBattlerAttacker].encoredMove; - gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; - *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); - } - // check if the encored move wasn't overwritten - else if (!gBattleStruct->zmove.active && gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE - && gDisableStructs[gBattlerAttacker].encoredMove != gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos]) - { - gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; - gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; - gDisableStructs[gBattlerAttacker].encoredMove = MOVE_NONE; - gDisableStructs[gBattlerAttacker].encoredMovePos = 0; - gDisableStructs[gBattlerAttacker].encoreTimer = 0; - *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); - } - else if (gBattleMons[gBattlerAttacker].moves[gCurrMovePos] != gChosenMoveByBattler[gBattlerAttacker]) - { - gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; - *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); - } - else - { - gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; - } - - // check z move used - if (gBattleStruct->zmove.toBeUsed[gBattlerAttacker] != MOVE_NONE && !IS_MOVE_STATUS(gCurrentMove)) - { - gCurrentMove = gBattleStruct->zmove.toBeUsed[gBattlerAttacker]; - } - - if (gBattleMons[gBattlerAttacker].hp != 0) - { - if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) - gBattleResults.lastUsedMovePlayer = gCurrentMove; - else - gBattleResults.lastUsedMoveOpponent = gCurrentMove; - } - - // Set dynamic move type. - SetTypeBeforeUsingMove(gChosenMove, gBattlerAttacker); - GET_MOVE_TYPE(gChosenMove, moveType); - - // TODO: Dynamax - // check max move used - // if (gBattleStruct->dynamax.usingMaxMove[gBattlerAttacker]) - // { - // gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove); - // gBattleStruct->dynamax.activeCategory = gBattleStruct->dynamax.categories[gBattlerAttacker]; - // } - - moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - - // choose target - side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker)); - if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove) - && moveTarget == MOVE_TARGET_SELECTED - && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget)) - { - gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = gSideTimers[side].followmeTarget; // follow me moxie fix - } - else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - && gSideTimers[side].followmeTimer == 0 - && (gMovesInfo[gCurrentMove].power != 0 || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS)) - && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) - || (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) - { - side = GetBattlerSide(gBattlerAttacker); - for (battler = 0; battler < gBattlersCount; battler++) - { - if (side != GetBattlerSide(battler) - && *(gBattleStruct->moveTarget + gBattlerAttacker) != battler - && ((GetBattlerAbility(battler) == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) - || (GetBattlerAbility(battler) == ABILITY_STORM_DRAIN && moveType == TYPE_WATER)) - && GetBattlerTurnOrderNum(battler) < var - && gMovesInfo[gCurrentMove].effect != EFFECT_SNIPE_SHOT - && gMovesInfo[gCurrentMove].effect != EFFECT_PLEDGE - && (GetBattlerAbility(gBattlerAttacker) != ABILITY_PROPELLER_TAIL - || GetBattlerAbility(gBattlerAttacker) != ABILITY_STALWART)) - { - var = GetBattlerTurnOrderNum(battler); - } - } - if (var == 4) - { - if (moveTarget & MOVE_TARGET_RANDOM) - { - if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) - { - if (Random() & 1) - gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - else - gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); - } - else - { - if (Random() & 1) - gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - else - gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); - } - } - else if (moveTarget & MOVE_TARGET_FOES_AND_ALLY) - { - for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) - { - if (gBattlerTarget == gBattlerAttacker) - continue; - if (IsBattlerAlive(gBattlerTarget)) - break; - } - } - else - { - gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); - } - - if (!IsBattlerAlive(gBattlerTarget)) - { - if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) - { - gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); - } - else - { - gBattlerTarget = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(gBattlerAttacker))); - if (!IsBattlerAlive(gBattlerTarget)) - gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); - } - } - } - else - { - u16 battlerAbility; - battler = gBattlerByTurnOrder[var]; - battlerAbility = GetBattlerAbility(battler); - - RecordAbilityBattle(battler, gBattleMons[battler].ability); - if (battlerAbility == ABILITY_LIGHTNING_ROD && gCurrentMove != MOVE_TEATIME) - gSpecialStatuses[battler].lightningRodRedirected = TRUE; - else if (battlerAbility == ABILITY_STORM_DRAIN) - gSpecialStatuses[battler].stormDrainRedirected = TRUE; - gBattlerTarget = battler; - } - } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && moveTarget & MOVE_TARGET_RANDOM) - { - if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) - { - if (Random() & 1) - gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - else - gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); - } - else - { - if (Random() & 1) - gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - else - gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); - } - - if (gAbsentBattlerFlags & gBitTable[gBattlerTarget] - && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) - { - gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); - } - } - else if (moveTarget == MOVE_TARGET_ALLY) - { - if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker))) - gBattlerTarget = BATTLE_PARTNER(gBattlerAttacker); - else - gBattlerTarget = gBattlerAttacker; - } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && moveTarget == MOVE_TARGET_FOES_AND_ALLY) - { - for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) - { - if (gBattlerTarget == gBattlerAttacker) - continue; - if (IsBattlerAlive(gBattlerTarget)) - break; - } - } - else - { - gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); - if (!IsBattlerAlive(gBattlerTarget)) - { - if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) - { - gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); - } - else - { - gBattlerTarget = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(gBattlerAttacker))); - if (!IsBattlerAlive(gBattlerTarget)) - gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); - } - } - } - - if (moveTarget == MOVE_TARGET_ALLY && gProtectStructs[BATTLE_PARTNER(gBattlerAttacker)].usedAllySwitch) - { - gBattlescriptCurrInstr = BattleScript_FailedFromAtkCanceler; - } - else - { - gBattlescriptCurrInstr = GET_MOVE_BATTLESCRIPT(gCurrentMove); - } - - for (i = 0; i < MAX_BATTLERS_COUNT; i++) - { - gBattleStruct->hpBefore[i] = gBattleMons[i].hp; - gSpecialStatuses[i].emergencyExited = FALSE; - } - - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; -} - -static void HandleAction_Switch(void) -{ - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - gBattle_BG0_X = 0; - gBattle_BG0_Y = 0; - gActionSelectionCursor[gBattlerAttacker] = 0; - gMoveSelectionCursor[gBattlerAttacker] = 0; - PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, *(gBattleStruct->battlerPartyIndexes + gBattlerAttacker)); - gBattleScripting.battler = gBattlerAttacker; - gBattlescriptCurrInstr = BattleScript_ActionSwitch; - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; - if (gBattleResults.playerSwitchesCounter < 255) - ++gBattleResults.playerSwitchesCounter; -} - -static void HandleAction_UseItem(void) -{ - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - gBattle_BG0_X = 0; - gBattle_BG0_Y = 0; - ClearVariousBattlerFlags(gBattlerAttacker); - - gLastUsedItem = gBattleResources->bufferB[gBattlerAttacker][1] | (gBattleResources->bufferB[gBattlerAttacker][2] << 8); - gBattlescriptCurrInstr = gBattlescriptsForUsingItem[ItemId_GetBattleUsage(gLastUsedItem) - 1]; - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; -} - -bool8 TryRunFromBattle(u8 battler) -{ - bool8 effect = FALSE; - u8 holdEffect; - u8 speedVar; - - if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY) - holdEffect = gEnigmaBerries[battler].holdEffect; - else - holdEffect = ItemId_GetHoldEffect(gBattleMons[battler].item); - gPotentialItemEffectBattler = battler; - if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) - { - gLastUsedItem = gBattleMons[battler].item; - gProtectStructs[battler].fleeType = FLEE_ITEM; - effect++; - } - else if (gBattleMons[battler].ability == ABILITY_RUN_AWAY) - { - gLastUsedAbility = ABILITY_RUN_AWAY; - gProtectStructs[battler].fleeType = FLEE_ABILITY; - effect++; - } - else if (IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(gBattleTypeFlags)) - { - if (GetBattlerSide(battler) == B_SIDE_PLAYER) - effect++; - } - else - { - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - { - if (gBattleMons[battler].speed < gBattleMons[BATTLE_OPPOSITE(battler)].speed) - { - speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30); - if (speedVar > (Random() & 0xFF)) - effect++; - } - else // same speed or faster - { - effect++; - } - } - - ++gBattleStruct->runTries; - } - if (effect != 0) - { - gCurrentTurnActionNumber = gBattlersCount; - gBattleOutcome = B_OUTCOME_RAN; - } - return effect; -} - -static void HandleAction_Run(void) -{ - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - - if (gBattleTypeFlags & BATTLE_TYPE_LINK) - { - u32 battler; - gCurrentTurnActionNumber = gBattlersCount; - for (battler = 0; battler < gBattlersCount; battler++) - { - if (GetBattlerSide(battler) == B_SIDE_PLAYER) - { - if (gChosenActionByBattler[battler] == B_ACTION_RUN) - gBattleOutcome |= B_OUTCOME_LOST; - } - else - { - if (gChosenActionByBattler[battler] == B_ACTION_RUN) - gBattleOutcome |= B_OUTCOME_WON; - } - } - gBattleOutcome |= B_OUTCOME_LINK_BATTLE_RAN; - } - else - { - if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) - { - if (!TryRunFromBattle(gBattlerAttacker)) // failed to run away - { - ClearVariousBattlerFlags(gBattlerAttacker); - gBattleCommunication[MULTISTRING_CHOOSER] = 3; - gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; - } - } - else - { - if (gBattleMons[gBattlerAttacker].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = 4; - gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; - } - else - { - gCurrentTurnActionNumber = gBattlersCount; - gBattleOutcome = B_OUTCOME_MON_FLED; - } - } - } -} - static void HandleAction_WatchesCarefully(void) { gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; diff --git a/src/battle_message.c b/src/battle_message.c index c4a61709b..f06f37b2f 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -3014,8 +3014,8 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst) { if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) { - if ((gBattleStruct->multiplayerId != 0 && (gPotentialItemEffectBattler & BIT_SIDE)) - || (gBattleStruct->multiplayerId == 0 && !(gPotentialItemEffectBattler & BIT_SIDE))) + if ((gBattleScripting.multiplayerId != 0 && (gPotentialItemEffectBattler & BIT_SIDE)) + || (gBattleScripting.multiplayerId == 0 && !(gPotentialItemEffectBattler & BIT_SIDE))) { StringCopy(text, gEnigmaBerries[gPotentialItemEffectBattler].name); StringAppend(text, sText_BerrySuffix); @@ -3028,7 +3028,7 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst) } else { - if (gLinkPlayers[gBattleStruct->multiplayerId].id == gPotentialItemEffectBattler) + if (gLinkPlayers[gBattleScripting.multiplayerId].id == gPotentialItemEffectBattler) { StringCopy(text, gEnigmaBerries[gPotentialItemEffectBattler].name); StringAppend(text, sText_BerrySuffix); @@ -3378,7 +3378,7 @@ static void ExpandBattleTextBuffPlaceholders(const u8 *src, u8 *dst) { if (hword == ITEM_ENIGMA_BERRY) { - if (gLinkPlayers[gBattleStruct->multiplayerId].id == gPotentialItemEffectBattler) + if (gLinkPlayers[gBattleScripting.multiplayerId].id == gPotentialItemEffectBattler) { StringCopy(dst, gEnigmaBerries[gPotentialItemEffectBattler].name); StringAppend(dst, sText_BerrySuffix); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index a38d2189e..9e73cbbd3 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -322,7 +322,6 @@ static const u16 sWhiteOutBadgeMoney[9] = { 8, 16, 24, 36, 48, 64, 80, 100, 120 #define TAG_LVLUP_BANNER_MON_ICON 55130 static void TrySetDestinyBondToHappen(void); -static u8 AttacksThisTurn(u8 battlerId, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr); static void InitLevelUpBanner(void); static bool8 SlideInLevelUpBanner(void); @@ -1982,19 +1981,6 @@ static void Cmd_damagecalc(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void AI_CalcDmg(u8 attacker, u8 defender) -{ - u32 sideStatus = gSideStatuses[GET_BATTLER_SIDE(defender)]; - u8 moveType; - s32 critChance; - - GET_MOVE_TYPE(gCurrentMove, moveType); - critChance = CalcCritChanceStage(attacker, defender, gCurrentMove, TRUE); - gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitChance[critChance] - 1, 1); - gBattleMoveDamage = CalculateMoveDamage(gCurrentMove, attacker, defender, moveType, 0, gIsCriticalHit, TRUE, TRUE); - CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE); -} - static void Cmd_typecalc(void) { CMD_ARGS(); @@ -2007,127 +1993,6 @@ static void Cmd_typecalc(void) gBattlescriptCurrInstr = cmd->nextInstr; } -// Same as ModulateDmgByType except different arguments -static void ModulateDmgByType2(uq4_12_t multiplier, u16 move, u8 *flags) -{ - gBattleMoveDamage = uq4_12_multiply(gBattleMoveDamage, multiplier); - if (gBattleMoveDamage == 0 && multiplier != 0) - gBattleMoveDamage = 1; - - switch (multiplier) - { - case UQ_4_12(0.0): - *flags |= MOVE_RESULT_DOESNT_AFFECT_FOE; - *flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; - *flags &= ~MOVE_RESULT_SUPER_EFFECTIVE; - break; - case UQ_4_12(0.5): - if (gMovesInfo[move].power && !(*flags & MOVE_RESULT_NO_EFFECT)) - { - if (*flags & MOVE_RESULT_SUPER_EFFECTIVE) - *flags &= ~MOVE_RESULT_SUPER_EFFECTIVE; - else - *flags |= MOVE_RESULT_NOT_VERY_EFFECTIVE; - } - break; - case UQ_4_12(2.0): - if (gMovesInfo[move].power && !(*flags & MOVE_RESULT_NO_EFFECT)) - { - if (*flags & MOVE_RESULT_NOT_VERY_EFFECTIVE) - *flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; - else - *flags |= MOVE_RESULT_SUPER_EFFECTIVE; - } - break; - } -} - -u8 TypeCalc(u16 move, u8 attacker, u8 defender) -{ - s32 i = 0; - u8 flags = 0; - u8 moveType; - - if (move == MOVE_STRUGGLE) - return 0; - - moveType = gMovesInfo[move].type; - - // check stab - if (IS_BATTLER_OF_TYPE(attacker, moveType)) - { - gBattleMoveDamage = gBattleMoveDamage * 15; - gBattleMoveDamage = gBattleMoveDamage / 10; - } - - if (gBattleMons[defender].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - flags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE); - } - else - { - ModulateDmgByType2(gTypeEffectivenessTable[moveType][gBattleMons[defender].type1], move, &flags); - ModulateDmgByType2(gTypeEffectivenessTable[moveType][gBattleMons[defender].type2], move, &flags); - } - - if (gBattleMons[defender].ability == ABILITY_WONDER_GUARD && !(flags & MOVE_RESULT_MISSED) - && AttacksThisTurn(attacker, move) == 2 - && (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE))) - && gMovesInfo[move].power) - { - flags |= MOVE_RESULT_MISSED; - } - return flags; -} - -u8 AI_TypeCalc(u16 move, u16 targetSpecies, u16 targetAbility) -{ - s32 i = 0; - u8 flags = 0; - u8 type1 = gSpeciesInfo[targetSpecies].types[0], type2 = gSpeciesInfo[targetSpecies].types[1]; - u8 moveType; - - if (move == MOVE_STRUGGLE) - return 0; - - moveType = gMovesInfo[move].type; - - if (targetAbility == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - flags = MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE; - } - else - { - ModulateDmgByType2(gTypeEffectivenessTable[moveType][type1], move, &flags); - ModulateDmgByType2(gTypeEffectivenessTable[moveType][type2], move, &flags); - } - if (targetAbility == ABILITY_WONDER_GUARD - && (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE))) - && gMovesInfo[move].power) - flags |= MOVE_RESULT_DOESNT_AFFECT_FOE; - return flags; -} - -// Multiplies the damage by a random factor between 85% to 100% inclusive -static inline void ApplyRandomDmgMultiplier(void) -{ - u16 rand = Random(); - u16 randPercent = 100 - (rand % 16); - - if (gBattleMoveDamage != 0) - { - gBattleMoveDamage *= randPercent; - gBattleMoveDamage /= 100; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - } -} - -static void Unused_ApplyRandomDmgMultiplier(void) -{ - ApplyRandomDmgMultiplier(); -} - static void Cmd_adjustdamage(void) { CMD_ARGS(); @@ -13081,24 +12946,6 @@ static void Cmd_copymovepermanently(void) } } -static u8 AttacksThisTurn(u8 battlerId, u16 move) // Note: returns 1 if it's a charging turn, otherwise 2 -{ - // first argument is unused - if (gMovesInfo[move].effect == EFFECT_SOLAR_BEAM - && (gBattleWeather & B_WEATHER_SUN)) - return 2; - - if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK - || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM - || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE - || gMovesInfo[move].effect == EFFECT_BIDE) - { - if ((gHitMarker & HITMARKER_CHARGING)) - return 1; - } - return 2; -} - static void Cmd_trychoosesleeptalkmove(void) { CMD_ARGS(const u8 *failInstr); diff --git a/src/battle_util.c b/src/battle_util.c index dbb4332e5..40e4207a8 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -51,6 +51,423 @@ static u8 CalcBeatUpPower(void) return basePower; } +bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) +{ + u32 ability = GetBattlerAbility(battlerAtk); + + if (gSideTimers[defSide].followmeTimer == 0 + || gBattleMons[gSideTimers[defSide].followmeTarget].hp == 0 + || gMovesInfo[move].effect == EFFECT_SNIPE_SHOT + || gMovesInfo[move].effect == EFFECT_SKY_DROP + || ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART) + return FALSE; + + if (gSideTimers[defSide].followmePowder && !IsAffectedByPowder(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk, TRUE))) + return FALSE; + + return TRUE; +} + +// Functions +void HandleAction_UseMove(void) +{ + u32 battler, i, side, moveType, var = 4; + u16 moveTarget; + + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + if (gBattleStruct->absentBattlerFlags & gBitTable[gBattlerAttacker] || !IsBattlerAlive(gBattlerAttacker)) + { + gCurrentActionFuncId = B_ACTION_FINISHED; + return; + } + + gIsCriticalHit = FALSE; + gBattleStruct->atkCancellerTracker = 0; + gMoveResultFlags = 0; + gMultiHitCounter = 0; + gBattleScripting.savedDmg = 0; + gBattleCommunication[MISS_TYPE] = 0; + gBattleScripting.savedMoveEffect = 0; + gCurrMovePos = gChosenMovePos = *(gBattleStruct->chosenMovePositions + gBattlerAttacker); + + // choose move + if (gProtectStructs[gBattlerAttacker].noValidMoves) + { + gProtectStructs[gBattlerAttacker].noValidMoves = FALSE; + gCurrentMove = gChosenMove = MOVE_STRUGGLE; + gHitMarker |= HITMARKER_NO_PPDEDUCT; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(MOVE_STRUGGLE, NO_TARGET_OVERRIDE); + } + else if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS || gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) + { + gCurrentMove = gChosenMove = gLockedMoves[gBattlerAttacker]; + } + // encore forces you to use the same move + else if (!gBattleStruct->zmove.active && gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE + && gDisableStructs[gBattlerAttacker].encoredMove == gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos]) + { + gCurrentMove = gChosenMove = gDisableStructs[gBattlerAttacker].encoredMove; + gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + } + // check if the encored move wasn't overwritten + else if (!gBattleStruct->zmove.active && gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE + && gDisableStructs[gBattlerAttacker].encoredMove != gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos]) + { + gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; + gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + gDisableStructs[gBattlerAttacker].encoredMove = MOVE_NONE; + gDisableStructs[gBattlerAttacker].encoredMovePos = 0; + gDisableStructs[gBattlerAttacker].encoreTimer = 0; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + } + else if (gBattleMons[gBattlerAttacker].moves[gCurrMovePos] != gChosenMoveByBattler[gBattlerAttacker]) + { + gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + } + else + { + gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + } + + // check z move used + if (gBattleStruct->zmove.toBeUsed[gBattlerAttacker] != MOVE_NONE && !IS_MOVE_STATUS(gCurrentMove)) + { + gCurrentMove = gBattleStruct->zmove.toBeUsed[gBattlerAttacker]; + } + + if (gBattleMons[gBattlerAttacker].hp != 0) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + gBattleResults.lastUsedMovePlayer = gCurrentMove; + else + gBattleResults.lastUsedMoveOpponent = gCurrentMove; + } + + // Set dynamic move type. + SetTypeBeforeUsingMove(gChosenMove, gBattlerAttacker); + GET_MOVE_TYPE(gChosenMove, moveType); + + // TODO: Dynamax + // check max move used + // if (gBattleStruct->dynamax.usingMaxMove[gBattlerAttacker]) + // { + // gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove); + // gBattleStruct->dynamax.activeCategory = gBattleStruct->dynamax.categories[gBattlerAttacker]; + // } + + moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); + + // choose target + side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker)); + if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove) + && moveTarget == MOVE_TARGET_SELECTED + && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget)) + { + gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = gSideTimers[side].followmeTarget; // follow me moxie fix + } + else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + && gSideTimers[side].followmeTimer == 0 + && (gMovesInfo[gCurrentMove].power != 0 || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS)) + && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) + || (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) + { + side = GetBattlerSide(gBattlerAttacker); + for (battler = 0; battler < gBattlersCount; battler++) + { + if (side != GetBattlerSide(battler) + && *(gBattleStruct->moveTarget + gBattlerAttacker) != battler + && ((GetBattlerAbility(battler) == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) + || (GetBattlerAbility(battler) == ABILITY_STORM_DRAIN && moveType == TYPE_WATER)) + && GetBattlerTurnOrderNum(battler) < var + && gMovesInfo[gCurrentMove].effect != EFFECT_SNIPE_SHOT + && gMovesInfo[gCurrentMove].effect != EFFECT_PLEDGE + && (GetBattlerAbility(gBattlerAttacker) != ABILITY_PROPELLER_TAIL + || GetBattlerAbility(gBattlerAttacker) != ABILITY_STALWART)) + { + var = GetBattlerTurnOrderNum(battler); + } + } + if (var == 4) + { + if (moveTarget & MOVE_TARGET_RANDOM) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + } + else + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + } + } + else if (moveTarget & MOVE_TARGET_FOES_AND_ALLY) + { + for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) + { + if (gBattlerTarget == gBattlerAttacker) + continue; + if (IsBattlerAlive(gBattlerTarget)) + break; + } + } + else + { + gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); + } + + if (!IsBattlerAlive(gBattlerTarget)) + { + if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + { + gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); + } + else + { + gBattlerTarget = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(gBattlerAttacker))); + if (!IsBattlerAlive(gBattlerTarget)) + gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); + } + } + } + else + { + u16 battlerAbility; + battler = gBattlerByTurnOrder[var]; + battlerAbility = GetBattlerAbility(battler); + + RecordAbilityBattle(battler, gBattleMons[battler].ability); + if (battlerAbility == ABILITY_LIGHTNING_ROD && gCurrentMove != MOVE_TEATIME) + gSpecialStatuses[battler].lightningRodRedirected = TRUE; + else if (battlerAbility == ABILITY_STORM_DRAIN) + gSpecialStatuses[battler].stormDrainRedirected = TRUE; + gBattlerTarget = battler; + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && moveTarget & MOVE_TARGET_RANDOM) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + } + else + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + } + + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget] + && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + { + gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); + } + } + else if (moveTarget == MOVE_TARGET_ALLY) + { + if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker))) + gBattlerTarget = BATTLE_PARTNER(gBattlerAttacker); + else + gBattlerTarget = gBattlerAttacker; + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && moveTarget == MOVE_TARGET_FOES_AND_ALLY) + { + for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) + { + if (gBattlerTarget == gBattlerAttacker) + continue; + if (IsBattlerAlive(gBattlerTarget)) + break; + } + } + else + { + gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); + if (!IsBattlerAlive(gBattlerTarget)) + { + if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + { + gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); + } + else + { + gBattlerTarget = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(gBattlerAttacker))); + if (!IsBattlerAlive(gBattlerTarget)) + gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); + } + } + } + + if (moveTarget == MOVE_TARGET_ALLY && gProtectStructs[BATTLE_PARTNER(gBattlerAttacker)].usedAllySwitch) + { + gBattlescriptCurrInstr = BattleScript_FailedFromAtkCanceler; + } + else + { + gBattlescriptCurrInstr = GET_MOVE_BATTLESCRIPT(gCurrentMove); + } + + for (i = 0; i < MAX_BATTLERS_COUNT; i++) + { + gBattleStruct->hpBefore[i] = gBattleMons[i].hp; + gSpecialStatuses[i].emergencyExited = FALSE; + } + + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +void HandleAction_Switch(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gActionSelectionCursor[gBattlerAttacker] = 0; + gMoveSelectionCursor[gBattlerAttacker] = 0; + + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, *(gBattleStruct->battlerPartyIndexes + gBattlerAttacker)) + + gBattleScripting.battler = gBattlerAttacker; + gBattlescriptCurrInstr = BattleScript_ActionSwitch; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + + if (gBattleResults.playerSwitchesCounter < 255) + gBattleResults.playerSwitchesCounter++; + + TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_SWITCH); +} + +void HandleAction_UseItem(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + ClearVariousBattlerFlags(gBattlerAttacker); + + gLastUsedItem = gBattleResources->bufferB[gBattlerAttacker][1] | (gBattleResources->bufferB[gBattlerAttacker][2] << 8); + gBattlescriptCurrInstr = gBattlescriptsForUsingItem[ItemId_GetBattleUsage(gLastUsedItem) - 1]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +bool8 TryRunFromBattle(u8 battler) +{ + bool8 effect = FALSE; + u8 holdEffect; + u8 speedVar; + + if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY) + holdEffect = gEnigmaBerries[battler].holdEffect; + else + holdEffect = ItemId_GetHoldEffect(gBattleMons[battler].item); + gPotentialItemEffectBattler = battler; + if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) + { + gLastUsedItem = gBattleMons[battler].item; + gProtectStructs[battler].fleeType = FLEE_ITEM; + effect++; + } + else if (gBattleMons[battler].ability == ABILITY_RUN_AWAY) + { + gLastUsedAbility = ABILITY_RUN_AWAY; + gProtectStructs[battler].fleeType = FLEE_ABILITY; + effect++; + } + else if (IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(gBattleTypeFlags)) + { + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + effect++; + } + else + { + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + if (gBattleMons[battler].speed < gBattleMons[BATTLE_OPPOSITE(battler)].speed) + { + speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30); + if (speedVar > (Random() & 0xFF)) + effect++; + } + else // same speed or faster + { + effect++; + } + } + + ++gBattleStruct->runTries; + } + if (effect != 0) + { + gCurrentTurnActionNumber = gBattlersCount; + gBattleOutcome = B_OUTCOME_RAN; + } + return effect; +} + +void HandleAction_Run(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + u32 battler; + gCurrentTurnActionNumber = gBattlersCount; + for (battler = 0; battler < gBattlersCount; battler++) + { + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + { + if (gChosenActionByBattler[battler] == B_ACTION_RUN) + gBattleOutcome |= B_OUTCOME_LOST; + } + else + { + if (gChosenActionByBattler[battler] == B_ACTION_RUN) + gBattleOutcome |= B_OUTCOME_WON; + } + } + gBattleOutcome |= B_OUTCOME_LINK_BATTLE_RAN; + } + else + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (!TryRunFromBattle(gBattlerAttacker)) // failed to run away + { + ClearVariousBattlerFlags(gBattlerAttacker); + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + } + } + else + { + if (gBattleMons[gBattlerAttacker].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + } + else + { + gCurrentTurnActionNumber = gBattlersCount; + gBattleOutcome = B_OUTCOME_MON_FLED; + } + } + } +} + + u8 GetBattlerForBattleScript(u8 caseId) { u8 ret = 0; @@ -10243,21 +10660,6 @@ bool32 CanBattlerEscape(u32 battler) // no ability check return TRUE; } -void SwitchPartyOrderInGameMulti(u8 battler, u8 arg1) -{ - if (GetBattlerSide(battler) != B_SIDE_OPPONENT) - { - s32 i; - for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++) - gBattlePartyCurrentOrder[i] = *(0 * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders)); - - SwitchPartyMonSlots(GetPartyIdFromBattlePartyId(gBattlerPartyIndexes[battler]), GetPartyIdFromBattlePartyId(arg1)); - - for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++) - *(0 * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders)) = gBattlePartyCurrentOrder[i]; - } -} - bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes) { bool32 ret = TRUE; @@ -10328,23 +10730,6 @@ s32 GetStealthHazardDamage(u8 hazardType, u32 battler) return GetStealthHazardDamageByTypesAndHP(hazardType, type1, type2, maxHp); } -bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) -{ - u32 ability = GetBattlerAbility(battlerAtk); - - if (gSideTimers[defSide].followmeTimer == 0 - || gBattleMons[gSideTimers[defSide].followmeTarget].hp == 0 - || gMovesInfo[move].effect == EFFECT_SNIPE_SHOT - || gMovesInfo[move].effect == EFFECT_SKY_DROP - || ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART) - return FALSE; - - if (gSideTimers[defSide].followmePowder && !IsAffectedByPowder(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk, TRUE))) - return FALSE; - - return TRUE; -} - bool32 DoBattlersShareType(u32 battler1, u32 battler2) { s32 i; @@ -10504,124 +10889,3 @@ bool32 CanUltraBurst(u32 battler) // No checks passed, the mon CAN'T ultra burst. return FALSE; } - - - -// battle_ai_util.c -// bool32 IsHealingMove(u32 move) -// { -// return gMovesInfo[move].healingMove; -// } - -// void RecordKnownMove(u32 battlerId, u32 move) -// { -// s32 i; -// for (i = 0; i < MAX_MON_MOVES; i++) -// { -// if (BATTLE_HISTORY->usedMoves[battlerId][i] == move) -// break; -// if (BATTLE_HISTORY->usedMoves[battlerId][i] == MOVE_NONE) -// { -// BATTLE_HISTORY->usedMoves[battlerId][i] = move; -// // TODO: AI -// // AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].moves[i] = move; -// break; -// } -// } -// } - -// s32 CountUsablePartyMons(u32 battlerId) -// { -// s32 battlerOnField1, battlerOnField2, i, ret; -// struct Pokemon *party; - -// if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) -// party = gPlayerParty; -// else -// party = gEnemyParty; - -// if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) -// { -// battlerOnField1 = gBattlerPartyIndexes[battlerId]; -// battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))]; -// } -// else // In singles there's only one battlerId by side. -// { -// battlerOnField1 = gBattlerPartyIndexes[battlerId]; -// battlerOnField2 = gBattlerPartyIndexes[battlerId]; -// } - -// ret = 0; -// for (i = 0; i < PARTY_SIZE; i++) -// { -// if (i != battlerOnField1 && i != battlerOnField2 -// && GetMonData(&party[i], MON_DATA_HP) != 0 -// && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE -// && GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG) -// { -// ret++; -// } -// } - -// return ret; -// } - -// bool32 IsAiVsAiBattle(void) -// { -// // TODO: Flag? -// return (B_FLAG_AI_VS_AI_BATTLE && FlagGet(B_FLAG_AI_VS_AI_BATTLE)); -// } - -// void RecordLastUsedMoveBy(u32 battlerId, u32 move) -// { -// u8 *index = &BATTLE_HISTORY->moveHistoryIndex[battlerId]; - -// if (++(*index) >= AI_MOVE_HISTORY_COUNT) -// *index = 0; -// BATTLE_HISTORY->moveHistory[battlerId][*index] = move; -// } - -// bool32 BattlerHasAi(u32 battlerId) -// { -// switch (GetBattlerPosition(battlerId)) -// { -// case B_POSITION_PLAYER_LEFT: -// if (IsAiVsAiBattle()) -// return TRUE; -// default: -// return FALSE; -// case B_POSITION_OPPONENT_LEFT: -// return TRUE; -// case B_POSITION_PLAYER_RIGHT: -// if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) || IsAiVsAiBattle()) -// return TRUE; -// else -// return FALSE; -// case B_POSITION_OPPONENT_RIGHT: -// return TRUE; -// } -// } - -// void ClearBattlerItemEffectHistory(u32 battlerId) -// { -// BATTLE_HISTORY->itemEffects[battlerId] = 0; -// } - -// // move checks -// bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect) -// { -// if (ability == ABILITY_OVERCOAT -// || (B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) -// || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES) -// return FALSE; -// return TRUE; -// } - -// void RecordAllMoves(u32 battler) -// { -// // TODO: AI -// // memcpy(AI_PARTY->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]].moves, gBattleMons[battler].moves, MAX_MON_MOVES * sizeof(u16)); -// } - - -// end battle_ai_util.c \ No newline at end of file diff --git a/src/battle_util2.c b/src/battle_util2.c index 05a38bfa6..2c5f647c5 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -3,6 +3,7 @@ #include "battle.h" #include "battle_anim.h" #include "malloc.h" +#include "party_menu.h" #include "pokemon.h" #include "trainer_tower.h" @@ -20,6 +21,10 @@ void AllocateBattleResources(void) gBattleStruct = AllocZeroed(sizeof(*gBattleStruct)); +#if B_FLAG_SKY_BATTLE + gBattleStruct->isSkyBattle = FlagGet(B_FLAG_SKY_BATTLE); +#endif + gBattleResources = AllocZeroed(sizeof(*gBattleResources)); gBattleResources->secretBase = AllocZeroed(sizeof(*gBattleResources->secretBase)); gBattleResources->flags = AllocZeroed(sizeof(*gBattleResources->flags)); @@ -27,8 +32,9 @@ void AllocateBattleResources(void) gBattleResources->battleCallbackStack = AllocZeroed(sizeof(*gBattleResources->battleCallbackStack)); gBattleResources->beforeLvlUp = AllocZeroed(sizeof(*gBattleResources->beforeLvlUp)); gBattleResources->ai = AllocZeroed(sizeof(*gBattleResources->ai)); + gBattleResources->aiData = AllocZeroed(sizeof(*gBattleResources->aiData)); + gBattleResources->aiParty = AllocZeroed(sizeof(*gBattleResources->aiParty)); gBattleResources->battleHistory = AllocZeroed(sizeof(*gBattleResources->battleHistory)); - gBattleResources->AI_ScriptsStack = AllocZeroed(sizeof(*gBattleResources->AI_ScriptsStack)); gLinkBattleSendBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE); gLinkBattleRecvBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE); @@ -53,6 +59,7 @@ void FreeBattleResources(void) FREE_AND_SET_NULL(gPokedudeBattlerStates[i]); } } + gFieldStatuses = 0; if (gBattleResources != NULL) { FREE_AND_SET_NULL(gBattleStruct); @@ -63,8 +70,9 @@ void FreeBattleResources(void) FREE_AND_SET_NULL(gBattleResources->battleCallbackStack); FREE_AND_SET_NULL(gBattleResources->beforeLvlUp); FREE_AND_SET_NULL(gBattleResources->ai); + FREE_AND_SET_NULL(gBattleResources->aiData); + FREE_AND_SET_NULL(gBattleResources->aiParty); FREE_AND_SET_NULL(gBattleResources->battleHistory); - FREE_AND_SET_NULL(gBattleResources->AI_ScriptsStack); FREE_AND_SET_NULL(gBattleResources); FREE_AND_SET_NULL(gLinkBattleSendBuffer); @@ -106,3 +114,18 @@ void AdjustFriendshipOnBattleFaint(u8 battler) AdjustFriendship(&gPlayerParty[gBattlerPartyIndexes[battler]], FRIENDSHIP_EVENT_FAINT_SMALL); } } + +void SwitchPartyOrderInGameMulti(u8 battler, u8 arg1) +{ + if (GetBattlerSide(battler) != B_SIDE_OPPONENT) + { + s32 i; + for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++) + gBattlePartyCurrentOrder[i] = *(0 * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders)); + + SwitchPartyMonSlots(GetPartyIdFromBattlePartyId(gBattlerPartyIndexes[battler]), GetPartyIdFromBattlePartyId(arg1)); + + for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++) + *(0 * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders)) = gBattlePartyCurrentOrder[i]; + } +} diff --git a/src/party_menu.c b/src/party_menu.c index bc2c3509c..18bdb52be 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -6449,7 +6449,7 @@ static bool8 TrySwitchInPokemon(void) StringExpandPlaceholders(gStringVar4, gText_EggCantBattle); return FALSE; } - if (GetPartyIdFromBattleSlot(slot) == gBattleStruct->playerPartyIdx) + if (GetPartyIdFromBattleSlot(slot) == gBattleStruct->prevSelectedPartySlot) { GetMonNickname(&gPlayerParty[slot], gStringVar1); StringExpandPlaceholders(gStringVar4, gText_PkmnAlreadySelected); diff --git a/src/quest_log_battle.c b/src/quest_log_battle.c index a06368a8c..615454734 100644 --- a/src/quest_log_battle.c +++ b/src/quest_log_battle.c @@ -128,7 +128,7 @@ void TrySetQuestLogLinkBattleEvent(void) } for (i = 0; i < PLAYER_NAME_LENGTH; i++) - data->playerNames[0][i] = gLinkPlayers[gBattleStruct->multiplayerId ^ 1].name[i]; + data->playerNames[0][i] = gLinkPlayers[gBattleScripting.multiplayerId ^ 1].name[i]; } SetQuestLogEvent(eventId, (const u16 *)data); Free(data); @@ -139,12 +139,12 @@ static void GetLinkMultiBattlePlayerIndexes(s32 * partnerIdx, s32 * opponentIdxs { s32 i; s32 numOpponentsFound = 0; - u8 partnerId = gLinkPlayers[gBattleStruct->multiplayerId].id ^ 2; + u8 partnerId = gLinkPlayers[gBattleScripting.multiplayerId].id ^ 2; for (i = 0; i < MAX_BATTLERS_COUNT; i++) { if (partnerId == gLinkPlayers[i].id) *partnerIdx = i; - else if (i != gBattleStruct->multiplayerId) + else if (i != gBattleScripting.multiplayerId) opponentIdxs[numOpponentsFound++] = i; } } From b0c55d4102a00042c32da2a7d5acf6da52c622ae Mon Sep 17 00:00:00 2001 From: cawtds Date: Sat, 11 May 2024 15:11:53 +0200 Subject: [PATCH 04/11] fixed AI related issues --- src/battle_main.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/battle_main.c b/src/battle_main.c index 71b7c0671..becda487f 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -2598,6 +2598,7 @@ void BeginBattleIntro(void) { BattleStartClearSetData(); gBattleCommunication[1] = 0; + gBattleStruct->introState = 0; gBattleMainFunc = BattleIntroGetMonsData; } @@ -2730,10 +2731,10 @@ static void BattleStartClearSetData(void) void SwitchInClearSetData(u32 battler) { - struct DisableStruct disableStructCopy = gDisableStructs[battler]; s32 i; - u8 *ptr; + struct DisableStruct disableStructCopy = gDisableStructs[battler]; + ClearIllusionMon(battler); if (gMovesInfo[gCurrentMove].effect != EFFECT_BATON_PASS) { for (i = 0; i < NUM_BATTLE_STATS; i++) @@ -2845,13 +2846,16 @@ void SwitchInClearSetData(u32 battler) // Reset damage to prevent things like red card activating if the switched-in mon is holding it gSpecialStatuses[battler].physicalDmg = 0; gSpecialStatuses[battler].specialDmg = 0; + gBattleStruct->enduredDamage &= ~gBitTable[battler]; + + // Reset G-Max Chi Strike boosts. + gBattleStruct->bonusCritStages[battler] = 0; // Reset G-Max Chi Strike boosts. gBattleStruct->bonusCritStages[battler] = 0; - // TODO: Dynamax // Reset Dynamax flags. - // UndoDynamax(battler); + UndoDynamax(battler); gBattleStruct->overwrittenAbilities[battler] = ABILITY_NONE; @@ -2917,12 +2921,12 @@ const u8* FaintClearSetData(u32 battler) gProtectStructs[battler].flinchImmobility = FALSE; gProtectStructs[battler].notFirstStrike = FALSE; gProtectStructs[battler].usedHealBlockedMove = FALSE; - gProtectStructs[battler].usesBouncedMove = FALSE; gProtectStructs[battler].usedGravityPreventedMove = FALSE; gProtectStructs[battler].usedThroatChopPreventedMove = FALSE; gProtectStructs[battler].statRaised = FALSE; gProtectStructs[battler].statFell = FALSE; gProtectStructs[battler].pranksterElevated = FALSE; + gProtectStructs[battler].usesBouncedMove = FALSE; // TODO remove gDisableStructs[battler].isFirstTurn = 2; @@ -2962,8 +2966,7 @@ const u8* FaintClearSetData(u32 battler) gBattleMons[battler].type2 = gSpeciesInfo[gBattleMons[battler].species].types[1]; gBattleMons[battler].type3 = TYPE_MYSTERY; - // TODO: AI - // Ai_UpdateFaintData(battler); + Ai_UpdateFaintData(battler); TryBattleFormChange(battler, FORM_CHANGE_FAINT); gBattleStruct->overwrittenAbilities[battler] = ABILITY_NONE; @@ -3325,7 +3328,26 @@ static void BattleIntroPlayerSendsOutMonAnimation(void) gBattleStruct->switchInAbilitiesCounter = 0; gBattleStruct->switchInItemsCounter = 0; gBattleStruct->overworldWeatherDone = FALSE; + SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers + Ai_InitPartyStruct(); // Save mons party counts, and first 2/4 mons on the battlefield. + // Try to set a status to start the battle with + gBattleStruct->startingStatus = 0; + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetTrainerStartingStatusFromId(gTrainerBattleOpponent_B)) + { + gBattleStruct->startingStatus = GetTrainerStartingStatusFromId(gTrainerBattleOpponent_B); + gBattleStruct->startingStatusTimer = 0; // infinite + } + else if (GetTrainerStartingStatusFromId(gTrainerBattleOpponent_A)) + { + gBattleStruct->startingStatus = GetTrainerStartingStatusFromId(gTrainerBattleOpponent_A); + gBattleStruct->startingStatusTimer = 0; // infinite + } + else if (B_VAR_STARTING_STATUS != 0) + { + gBattleStruct->startingStatus = VarGet(B_VAR_STARTING_STATUS); + gBattleStruct->startingStatusTimer = VarGet(B_VAR_STARTING_STATUS_TIMER); + } gBattleMainFunc = TryDoEventsBeforeFirstTurn; } @@ -3478,6 +3500,7 @@ void BattleTurnPassed(void) *(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE; *(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags; + SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers gBattleMainFunc = HandleTurnActionSelectionState; } From 94cebee47556111c7b0d15f9305a1d873273c1fa Mon Sep 17 00:00:00 2001 From: cawtds Date: Sat, 11 May 2024 16:32:29 +0200 Subject: [PATCH 05/11] updated battle intro --- data/maps/ViridianCity_Mart/scripts.inc | 1 + include/battle_util.h | 1 + src/battle_main.c | 694 +++++++++++++----------- src/battle_util.c | 8 + 4 files changed, 379 insertions(+), 325 deletions(-) diff --git a/data/maps/ViridianCity_Mart/scripts.inc b/data/maps/ViridianCity_Mart/scripts.inc index 928c1f6da..d51ddc267 100644 --- a/data/maps/ViridianCity_Mart/scripts.inc +++ b/data/maps/ViridianCity_Mart/scripts.inc @@ -102,6 +102,7 @@ ViridianCity_Mart_Items:: .2byte ITEM_MEGA_RING .2byte ITEM_CHARIZARDITE_X .2byte ITEM_CHARIZARDITE_Y + .2byte ITEM_SILPH_SCOPE .2byte ITEM_NONE release end diff --git a/include/battle_util.h b/include/battle_util.h index bb18ee01f..1795ebacb 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -127,6 +127,7 @@ bool8 TryRunFromBattle(u8 battler); void HandleAction_Run(void); u8 GetBattlerForBattleScript(u8 caseId); +bool32 IsBattlerMarkedForControllerExec(u32 battler); void MarkBattlerForControllerExec(u8 battlerId); void MarkBattlerReceivedLinkData(u8 battlerId); const u8* CancelMultiTurnMoves(u32 battler); diff --git a/src/battle_main.c b/src/battle_main.c index becda487f..2b13d3d8e 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -30,6 +30,7 @@ #include "roamer.h" #include "safari_zone.h" #include "scanline_effect.h" +#include "strings.h" #include "task.h" #include "trig.h" #include "vs_seeker.h" @@ -81,18 +82,9 @@ static void SpriteCB_Idle(struct Sprite *sprite); static void SpriteCB_BounceEffect(struct Sprite *sprite); static void SpriteCB_PlayerThrowUpdate(struct Sprite *sprite); static void BattleStartClearSetData(void); -static void BattleIntroGetMonsData(void); +static void DoBattleIntro(void); static void TurnValuesCleanUp(bool8 var0); -static void BattleIntroPrepareBackgroundSlide(void); -static void BattleIntroDrawTrainersOrMonsSprites(void); static void BattleIntroDrawPartySummaryScreens(void); -static void BattleIntroPrintTrainerWantsToBattle(void); -static void BattleIntroPrintWildMonAttacked(void); -static void BattleIntroPrintOpponentSendsOut(void); -static void BattleIntroPrintPlayerSendsOut(void); -static void BattleIntroRecordMonsToDex(void); -static void BattleIntroOpponentSendsOutMonAnimation(void); -static void BattleIntroPlayerSendsOutMonAnimation(void); static void TryDoEventsBeforeFirstTurn(void); static void HandleTurnActionSelectionState(void); static void RunTurnActionsFunctions(void); @@ -2599,7 +2591,7 @@ void BeginBattleIntro(void) BattleStartClearSetData(); gBattleCommunication[1] = 0; gBattleStruct->introState = 0; - gBattleMainFunc = BattleIntroGetMonsData; + gBattleMainFunc = DoBattleIntro; } static void BattleMainCB1(void) @@ -3017,338 +3009,330 @@ const u8* FaintClearSetData(u32 battler) return result; } -static void BattleIntroGetMonsData(void) +static void DoBattleIntro(void) { - switch (gBattleCommunication[MULTIUSE_STATE]) + s32 i; + u32 battler; + u8 *state = &gBattleStruct->introState; + + switch (*state) { - case 0: - { - u32 battler = gBattleCommunication[1]; + case 0: // Get Data of all battlers. + battler = gBattleCommunication[1]; BtlController_EmitGetMonData(battler, BUFFER_A, REQUEST_ALL_BATTLE, 0); MarkBattlerForControllerExec(battler); - gBattleCommunication[MULTIUSE_STATE]++; + (*state)++; break; - } - case 1: - if (gBattleControllerExecFlags == 0) + case 1: // Loop through all battlers. + if (!gBattleControllerExecFlags) { - gBattleCommunication[1]++; - if (gBattleCommunication[1] == gBattlersCount) - gBattleMainFunc = BattleIntroPrepareBackgroundSlide; + if (++gBattleCommunication[1] == gBattlersCount) + (*state)++; else - gBattleCommunication[MULTIUSE_STATE] = 0; + *state = 0; } break; - } -} - -static void BattleIntroPrepareBackgroundSlide(void) -{ - if (gBattleControllerExecFlags == 0) - { - u32 battler = GetBattlerAtPosition(0); - BtlController_EmitIntroSlide(battler, BUFFER_A, gBattleTerrain); - MarkBattlerForControllerExec(battler); - gBattleMainFunc = BattleIntroDrawTrainersOrMonsSprites; - gBattleCommunication[MULTIUSE_STATE] = 0; - gBattleCommunication[SPRITES_INIT_STATE1] = 0; - } -} - -static void BattleIntroDrawTrainersOrMonsSprites(void) -{ - u32 battler; - u8 *ptr; - s32 i; - - if (gBattleControllerExecFlags) - return; - - for (battler = 0; battler < gBattlersCount; battler++) - { - if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) - && GetBattlerSide(battler) == B_SIDE_PLAYER) + case 2: // Start graphical intro slide. + if (!gBattleControllerExecFlags) { - ptr = (u8 *)&gBattleMons[battler]; - for (i = 0; i < sizeof(struct BattlePokemon); i++) - ptr[i] = 0; - } - else - { - u16 *hpOnSwitchout; - - ptr = (u8 *)&gBattleMons[battler]; - for (i = 0; i < sizeof(struct BattlePokemon); i++) - ptr[i] = gBattleResources->bufferB[battler][4 + i]; - - gBattleMons[battler].type1 = gSpeciesInfo[gBattleMons[battler].species].types[0]; - gBattleMons[battler].type2 = gSpeciesInfo[gBattleMons[battler].species].types[1]; - gBattleMons[battler].type3 = TYPE_MYSTERY; - gBattleMons[battler].ability = GetAbilityBySpecies(gBattleMons[battler].species, gBattleMons[battler].abilityNum); - hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBattlerSide(battler)]; - *hpOnSwitchout = gBattleMons[battler].hp; - for (i = 0; i < NUM_BATTLE_STATS; i++) - gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; - gBattleMons[battler].status2 = 0; - } - - if (GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT) - { - BtlController_EmitDrawTrainerPic(battler, BUFFER_A); + battler = GetBattlerAtPosition(0); + BtlController_EmitIntroSlide(battler, BUFFER_A, gBattleTerrain); MarkBattlerForControllerExec(battler); + gBattleCommunication[0] = 0; + gBattleCommunication[1] = 0; + (*state)++; + } + break; + case 3: // Wait for intro slide. + if (!gBattleControllerExecFlags) + (*state)++; + break; + case 4: // Copy battler data gotten in cases 0 and 1. Draw trainer/mon sprite. + for (battler = 0; battler < gBattlersCount; battler++) + { + if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) && GetBattlerSide(battler) == B_SIDE_PLAYER) + { + memset(&gBattleMons[battler], 0, sizeof(struct BattlePokemon)); + } + else + { + memcpy(&gBattleMons[battler], &gBattleResources->bufferB[battler][4], sizeof(struct BattlePokemon)); + gBattleMons[battler].type1 = gSpeciesInfo[gBattleMons[battler].species].types[0]; + gBattleMons[battler].type2 = gSpeciesInfo[gBattleMons[battler].species].types[1]; + gBattleMons[battler].type3 = TYPE_MYSTERY; + gBattleMons[battler].ability = GetAbilityBySpecies(gBattleMons[battler].species, gBattleMons[battler].abilityNum); + gBattleStruct->hpOnSwitchout[GetBattlerSide(battler)] = gBattleMons[battler].hp; + gBattleMons[battler].status2 = 0; + for (i = 0; i < NUM_BATTLE_STATS; i++) + gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; + } + + // Draw sprite. + switch (GetBattlerPosition(battler)) + { + case B_POSITION_PLAYER_LEFT: // player sprite + BtlController_EmitDrawTrainerPic(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + break; + case B_POSITION_OPPONENT_LEFT: + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) // opponent 1 sprite + { + BtlController_EmitDrawTrainerPic(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + } + else // wild mon 1 + { + BtlController_EmitLoadMonSprite(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES, NULL); + } + break; + case B_POSITION_PLAYER_RIGHT: + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER)) // partner sprite + { + BtlController_EmitDrawTrainerPic(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + } + break; + case B_POSITION_OPPONENT_RIGHT: + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) // opponent 2 if exists + { + BtlController_EmitDrawTrainerPic(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + } + } + else if (IsBattlerAlive(battler)) // wild mon 2 if alive + { + BtlController_EmitLoadMonSprite(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES, NULL); + } + break; + } } if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { - if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT) + (*state)++; + } + else // Skip party summary since it is a wild battle. + { + if (B_FAST_INTRO == TRUE) + *state = 7; // Don't wait for sprite, print message at the same time. + else + *state = 6; // Wait for sprite to load. + } + break; + case 5: // draw party summary in trainer battles + if (!gBattleControllerExecFlags) + { + struct HpAndStatus hpStatus[PARTY_SIZE]; + + for (i = 0; i < PARTY_SIZE; i++) { - BtlController_EmitDrawTrainerPic(battler, BUFFER_A); - MarkBattlerForControllerExec(battler); + if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE + || GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) + { + hpStatus[i].hp = HP_EMPTY_SLOT; + hpStatus[i].status = 0; + } + else + { + hpStatus[i].hp = GetMonData(&gEnemyParty[i], MON_DATA_HP); + hpStatus[i].status = GetMonData(&gEnemyParty[i], MON_DATA_STATUS); + } } - if (GetBattlerSide(battler) == B_SIDE_OPPONENT - && !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER + + battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + BtlController_EmitDrawPartyStatusSummary(battler, BUFFER_A, hpStatus, PARTY_SUMM_SKIP_DRAW_DELAY); + MarkBattlerForControllerExec(battler); + + for (i = 0; i < PARTY_SIZE; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE + || GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) + { + hpStatus[i].hp = HP_EMPTY_SLOT; + hpStatus[i].status = 0; + } + else + { + hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); + hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); + } + } + + battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + BtlController_EmitDrawPartyStatusSummary(battler, BUFFER_A, hpStatus, PARTY_SUMM_SKIP_DRAW_DELAY); + MarkBattlerForControllerExec(battler); + + (*state)++; + } + break; + case 6: // wait for previous action to complete + if (!gBattleControllerExecFlags) + (*state)++; + break; + case 7: // print battle intro message + if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT))) + { + PrepareStringBattle(STRINGID_INTROMSG, GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)); + (*state)++; + } + break; + case 8: // wait for intro message to be printed + if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT))) + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + (*state)++; + } + else + { + if (B_FAST_INTRO == TRUE) + *state = 15; // Wait for text to be printed. + else + *state = 14; // Wait for text and sprite. + } + } + break; + case 9: // print opponent sends out + PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)); + (*state)++; + break; + case 10: // wait for opponent sends out text + if (!gBattleControllerExecFlags) + (*state)++; + break; + case 11: // first opponent's mon send out animation + battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + + BtlController_EmitIntroTrainerBallThrow(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + (*state)++; + break; + case 12: // nothing + (*state)++; + case 13: // second opponent's mon send out + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) + { + battler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + + BtlController_EmitIntroTrainerBallThrow(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + } + if (B_FAST_INTRO == TRUE + && !(gBattleTypeFlags & BATTLE_TYPE_LINK)) + *state = 15; // Print at the same time as trainer sends out second mon. + else + (*state)++; + break; + case 14: // wait for opponent 2 send out + if (!gBattleControllerExecFlags) + (*state)++; + break; + case 15: // wait for wild battle message + if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT))) + { + if (IS_BATTLE_TYPE_GHOST_WITH_SCOPE(gBattleTypeFlags)) + { + gBattleScripting.battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + BattleScriptExecute(BattleScript_SilphScopeUnveiled); + } + (*state)++; + } + break; + case 16: // print player sends out + if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) + { + battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + + // A hack that makes fast intro work in trainer battles too. + if (B_FAST_INTRO == TRUE + && gBattleTypeFlags & BATTLE_TYPE_TRAINER + && !(gBattleTypeFlags & BATTLE_TYPE_LINK) + && gSprites[gHealthboxSpriteIds[battler ^ BIT_SIDE]].callback == SpriteCallbackDummy) + { + return; + } + + PrepareStringBattle(STRINGID_INTROSENDOUT, battler); + } + (*state)++; + break; + case 17: // wait for player send out message + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleControllerExecFlags)) + { + battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + + if (!IsBattlerMarkedForControllerExec(battler)) + (*state)++; + } + break; + case 18: // player 1 send out + battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + + BtlController_EmitIntroTrainerBallThrow(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + (*state)++; + break; + case 19: // player 2 send out + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER)) + { + battler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + + BtlController_EmitIntroTrainerBallThrow(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + } + (*state)++; + break; + case 20: // set dex and battle vars + if (!gBattleControllerExecFlags) + { + for (battler = 0; battler < gBattlersCount; battler++) + { + if (GetBattlerSide(battler) == B_SIDE_OPPONENT + && (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_POKEDUDE | BATTLE_TYPE_LINK | BATTLE_TYPE_GHOST | BATTLE_TYPE_OLD_MAN_TUTORIAL - | BATTLE_TYPE_LEGENDARY))) - { - HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality); - } - } - else - { - if (GetBattlerSide(battler) == B_SIDE_OPPONENT) - { - if (gBattleTypeFlags & (BATTLE_TYPE_GHOST | BATTLE_TYPE_GHOST_UNVEILED)) - { - if (!IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(gBattleTypeFlags)) - HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality); - } - else if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_POKEDUDE - | BATTLE_TYPE_LINK - | BATTLE_TYPE_GHOST - | BATTLE_TYPE_OLD_MAN_TUTORIAL - | BATTLE_TYPE_LEGENDARY))) + | BATTLE_TYPE_LEGENDARY)) + || ((gBattleTypeFlags & (BATTLE_TYPE_GHOST | BATTLE_TYPE_GHOST_UNVEILED)) && !IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(gBattleTypeFlags)))) { HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality); } - BtlController_EmitLoadMonSprite(battler, 0); - MarkBattlerForControllerExec(battler); } - } - if (gBattleTypeFlags & BATTLE_TYPE_MULTI - && (GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT || GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT)) - { - BtlController_EmitDrawTrainerPic(battler, BUFFER_A); - MarkBattlerForControllerExec(battler); - } - } - gBattleMainFunc = BattleIntroDrawPartySummaryScreens; -} -static void BattleIntroDrawPartySummaryScreens(void) -{ - u32 battler; - s32 i; - struct HpAndStatus hpStatus[PARTY_SIZE]; + gBattleStruct->switchInAbilitiesCounter = 0; + gBattleStruct->switchInItemsCounter = 0; + gBattleStruct->overworldWeatherDone = FALSE; + SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers + Ai_InitPartyStruct(); // Save mons party counts, and first 2/4 mons on the battlefield. - if (gBattleControllerExecFlags) - return; - - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) - { - for (i = 0; i < PARTY_SIZE; i++) - { - if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE - || GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) + // Try to set a status to start the battle with + gBattleStruct->startingStatus = 0; + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetTrainerStartingStatusFromId(gTrainerBattleOpponent_B)) { - hpStatus[i].hp = HP_EMPTY_SLOT; - hpStatus[i].status = 0; + gBattleStruct->startingStatus = GetTrainerStartingStatusFromId(gTrainerBattleOpponent_B); + gBattleStruct->startingStatusTimer = 0; // infinite } - else + else if (GetTrainerStartingStatusFromId(gTrainerBattleOpponent_A)) { - hpStatus[i].hp = GetMonData(&gEnemyParty[i], MON_DATA_HP); - hpStatus[i].status = GetMonData(&gEnemyParty[i], MON_DATA_STATUS); + gBattleStruct->startingStatus = GetTrainerStartingStatusFromId(gTrainerBattleOpponent_A); + gBattleStruct->startingStatusTimer = 0; // infinite } - } - battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - BtlController_EmitDrawPartyStatusSummary(battler, BUFFER_A, hpStatus, PARTY_SUMM_SKIP_DRAW_DELAY); - MarkBattlerForControllerExec(battler); - - for (i = 0; i < PARTY_SIZE; i++) - { - if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE - || GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) + else if (B_VAR_STARTING_STATUS != 0) { - hpStatus[i].hp = HP_EMPTY_SLOT; - hpStatus[i].status = 0; - } - else - { - hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); - hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); + gBattleStruct->startingStatus = VarGet(B_VAR_STARTING_STATUS); + gBattleStruct->startingStatusTimer = VarGet(B_VAR_STARTING_STATUS_TIMER); } + gBattleMainFunc = TryDoEventsBeforeFirstTurn; } - battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - BtlController_EmitDrawPartyStatusSummary(battler, BUFFER_A, hpStatus, PARTY_SUMM_SKIP_DRAW_DELAY); - MarkBattlerForControllerExec(battler); - - gBattleMainFunc = BattleIntroPrintTrainerWantsToBattle; + break; } - else - { - // The struct gets set here, but nothing is ever done with it since - // wild battles don't show the party summary. - // Still, there's no point in having dead code. - - for (i = 0; i < PARTY_SIZE; i++) - { - if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE - || GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) - { - hpStatus[i].hp = HP_EMPTY_SLOT; - hpStatus[i].status = 0; - } - else - { - hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP); - hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS); - } - } - - gBattleMainFunc = BattleIntroPrintWildMonAttacked; - } -} - -static void BattleIntroPrintTrainerWantsToBattle(void) -{ - if (gBattleControllerExecFlags == 0) - { - u32 battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - PrepareStringBattle(STRINGID_INTROMSG, battler); - gBattleMainFunc = BattleIntroPrintOpponentSendsOut; - } -} - -static void BattleIntroPrintWildMonAttacked(void) -{ - if (gBattleControllerExecFlags == 0) - { - gBattleMainFunc = BattleIntroPrintPlayerSendsOut; - PrepareStringBattle(STRINGID_INTROMSG, 0); - if (IS_BATTLE_TYPE_GHOST_WITH_SCOPE(gBattleTypeFlags)) - { - gBattleScripting.battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - BattleScriptExecute(BattleScript_SilphScopeUnveiled); - } - } -} - -static void BattleIntroPrintOpponentSendsOut(void) -{ - if (gBattleControllerExecFlags == 0) - { - PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)); - gBattleMainFunc = BattleIntroOpponentSendsOutMonAnimation; - } -} - -static void BattleIntroOpponentSendsOutMonAnimation(void) -{ - if (gBattleControllerExecFlags == 0) - { - u32 battler; - for (battler = 0; battler < gBattlersCount; battler++) - { - if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT) - { - BtlController_EmitIntroTrainerBallThrow(battler, 0); - MarkBattlerForControllerExec(battler); - } - if (gBattleTypeFlags & BATTLE_TYPE_MULTI && GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT) - { - BtlController_EmitIntroTrainerBallThrow(battler, 0); - MarkBattlerForControllerExec(battler); - } - } - gBattleMainFunc = BattleIntroRecordMonsToDex; - } -} - -static void BattleIntroRecordMonsToDex(void) -{ - if (gBattleControllerExecFlags == 0) - { - u32 battler; - for (battler = 0; battler < gBattlersCount; battler++) - if (GetBattlerSide(battler) == B_SIDE_OPPONENT - && !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_POKEDUDE - | BATTLE_TYPE_LINK - | BATTLE_TYPE_GHOST - | BATTLE_TYPE_OLD_MAN_TUTORIAL - | BATTLE_TYPE_LEGENDARY))) - HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality); - gBattleMainFunc = BattleIntroPrintPlayerSendsOut; - } -} - -static void BattleIntroPrintPlayerSendsOut(void) -{ - if (gBattleControllerExecFlags == 0) - { - if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) - PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)); - gBattleMainFunc = BattleIntroPlayerSendsOutMonAnimation; - } -} - -static void BattleIntroPlayerSendsOutMonAnimation(void) -{ - u32 position, battler; - - if (gBattleControllerExecFlags) - return; - - for (battler = 0; battler < gBattlersCount; battler++) - { - if (GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT) - { - BtlController_EmitIntroTrainerBallThrow(battler, 0); - MarkBattlerForControllerExec(battler); - } - if (gBattleTypeFlags & BATTLE_TYPE_MULTI && GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT) - { - BtlController_EmitIntroTrainerBallThrow(battler, 0); - MarkBattlerForControllerExec(battler); - } - } - gBattleStruct->switchInAbilitiesCounter = 0; - gBattleStruct->switchInItemsCounter = 0; - gBattleStruct->overworldWeatherDone = FALSE; - SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers - Ai_InitPartyStruct(); // Save mons party counts, and first 2/4 mons on the battlefield. - - // Try to set a status to start the battle with - gBattleStruct->startingStatus = 0; - if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetTrainerStartingStatusFromId(gTrainerBattleOpponent_B)) - { - gBattleStruct->startingStatus = GetTrainerStartingStatusFromId(gTrainerBattleOpponent_B); - gBattleStruct->startingStatusTimer = 0; // infinite - } - else if (GetTrainerStartingStatusFromId(gTrainerBattleOpponent_A)) - { - gBattleStruct->startingStatus = GetTrainerStartingStatusFromId(gTrainerBattleOpponent_A); - gBattleStruct->startingStatusTimer = 0; // infinite - } - else if (B_VAR_STARTING_STATUS != 0) - { - gBattleStruct->startingStatus = VarGet(B_VAR_STARTING_STATUS); - gBattleStruct->startingStatusTimer = VarGet(B_VAR_STARTING_STATUS_TIMER); - } - gBattleMainFunc = TryDoEventsBeforeFirstTurn; } static void TryDoEventsBeforeFirstTurn(void) @@ -3359,45 +3343,89 @@ static void TryDoEventsBeforeFirstTurn(void) if (gBattleControllerExecFlags) return; + // Set invalid mons as absent(for example when starting a double battle with only one pokemon). + if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) + { + for (i = 0; i < gBattlersCount; i++) + { + struct Pokemon *party = GetBattlerParty(i); + struct Pokemon *mon = &party[gBattlerPartyIndexes[i]]; + if (gBattleMons[i].hp == 0 || gBattleMons[i].species == SPECIES_NONE || GetMonData(mon, MON_DATA_IS_EGG)) + gAbsentBattlerFlags |= gBitTable[i]; + } + } + if (gBattleStruct->switchInAbilitiesCounter == 0) { for (i = 0; i < gBattlersCount; i++) gBattlerByTurnOrder[i] = i; for (i = 0; i < gBattlersCount - 1; i++) + { for (j = i + 1; j < gBattlersCount; j++) - if ((GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) == 1) != 0) + { + if (GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) == -1) SwapTurnOrder(i, j); + } + } } if (!gBattleStruct->overworldWeatherDone - && AbilityBattleEffects(0, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0) + && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_WEATHER, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0) { gBattleStruct->overworldWeatherDone = TRUE; return; } + + if (!gBattleStruct->terrainDone && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_TERRAIN, 0, 0, ABILITYEFFECT_SWITCH_IN_TERRAIN, 0) != 0) + { + gBattleStruct->terrainDone = TRUE; + return; + } + + if (!gBattleStruct->startingStatusDone + && gBattleStruct->startingStatus + && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_STATUSES, 0, 0, ABILITYEFFECT_SWITCH_IN_STATUSES, 0) != 0) + { + gBattleStruct->startingStatusDone = TRUE; + return; + } + + // Totem boosts + for (i = 0; i < gBattlersCount; i++) + { + if (gQueuedStatBoosts[i].stats != 0 && !gProtectStructs[i].eatMirrorHerb && gProtectStructs[i].activateOpportunist == 0) + { + gBattlerAttacker = i; + BattleScriptExecute(BattleScript_TotemVar); + return; + } + } + + // Check neutralizing gas + if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, 0, 0, 0, 0) != 0) + return; + // Check all switch in abilities happening from the fastest mon to slowest. while (gBattleStruct->switchInAbilitiesCounter < gBattlersCount) { - if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBattlerByTurnOrder[gBattleStruct->switchInAbilitiesCounter], 0, 0, 0) != 0) - effect++; - ++gBattleStruct->switchInAbilitiesCounter; - if (effect != 0) + gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->switchInAbilitiesCounter++]; + + if (TryPrimalReversion(gBattlerAttacker)) + return; + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBattlerAttacker, 0, 0, 0) != 0) return; } - if (AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE1, 0, 0, 0, 0) != 0) - return; - if (AbilityBattleEffects(ABILITYEFFECT_TRACE, 0, 0, 0, 0) != 0) + if (AbilityBattleEffects(ABILITYEFFECT_TRACE1, 0, 0, 0, 0) != 0) return; // Check all switch in items having effect from the fastest mon to slowest. while (gBattleStruct->switchInItemsCounter < gBattlersCount) { - if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gBattlerByTurnOrder[gBattleStruct->switchInItemsCounter], FALSE)) - effect++; - ++gBattleStruct->switchInItemsCounter; - if (effect != 0) + if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gBattlerByTurnOrder[gBattleStruct->switchInItemsCounter++], FALSE)) return; } - for (i = 0; i < gBattlersCount; i++) // pointless, ruby leftover - ; + + if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0)) + return; + for (i = 0; i < MAX_BATTLERS_COUNT; i++) { *(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE; @@ -3407,12 +3435,21 @@ static void TryDoEventsBeforeFirstTurn(void) TurnValuesCleanUp(FALSE); SpecialStatusesClear(); *(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags; + BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); gBattleMainFunc = HandleTurnActionSelectionState; ResetSentPokesToOpponentValue(); + for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++) gBattleCommunication[i] = 0; + for (i = 0; i < gBattlersCount; i++) - gBattleMons[i].status2 &= ~(STATUS2_FLINCHED); + { + gBattleMons[i].status2 &= ~STATUS2_FLINCHED; + // Record party slots of player's mons that appeared in battle + if (!BattlerHasAi(i)) + gBattleStruct->appearedInBattle |= gBitTable[gBattlerPartyIndexes[i]]; + } + *(&gBattleStruct->turnEffectsTracker) = 0; *(&gBattleStruct->turnEffectsBattlerId) = 0; *(&gBattleStruct->wishPerishSongState) = 0; @@ -3421,7 +3458,14 @@ static void TryDoEventsBeforeFirstTurn(void) gBattleStruct->faintedActionsState = 0; gBattleStruct->turnCountersTracker = 0; gMoveResultFlags = 0; - gRandomTurnNumber = Random(); + + memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); // erase all totem boosts just to be safe + + SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers + + // TODO: Trainer slide + // if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_BEFORE_FIRST_TURN))) + // BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2); } static void HandleEndTurn_ContinueBattle(void) diff --git a/src/battle_util.c b/src/battle_util.c index 40e4207a8..1dd2c6b48 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -518,6 +518,14 @@ u8 GetBattlerForBattleScript(u8 caseId) return ret; } +bool32 IsBattlerMarkedForControllerExec(u32 battler) +{ + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + return (gBattleControllerExecFlags & (gBitTable[battler] << 0x1C)) != 0; + else + return (gBattleControllerExecFlags & (gBitTable[battler])) != 0; +} + void MarkBattlerForControllerExec(u8 battlerId) { if (gBattleTypeFlags & BATTLE_TYPE_LINK) From a657e5927735928621299795adf08d49e6b61cd3 Mon Sep 17 00:00:00 2001 From: cawtds Date: Sat, 11 May 2024 16:50:39 +0200 Subject: [PATCH 06/11] battle_main updates --- src/battle_main.c | 5 ++- src/battle_util.c | 101 +++++++++++++++++++--------------------------- 2 files changed, 45 insertions(+), 61 deletions(-) diff --git a/src/battle_main.c b/src/battle_main.c index 2b13d3d8e..0049fedd4 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3479,7 +3479,7 @@ static void HandleEndTurn_ContinueBattle(void) gBattleCommunication[i] = 0; for (i = 0; i < gBattlersCount; i++) { - gBattleMons[i].status2 &= ~(STATUS2_FLINCHED); + gBattleMons[i].status2 &= ~STATUS2_FLINCHED; if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].status2 & STATUS2_MULTIPLETURNS)) CancelMultiTurnMoves(i); } @@ -3532,7 +3532,7 @@ void BattleTurnPassed(void) } if (gBattleResults.battleTurnCounter < 0xFF) - ++gBattleResults.battleTurnCounter; + gBattleResults.battleTurnCounter++; for (i = 0; i < gBattlersCount; i++) { @@ -3544,6 +3544,7 @@ void BattleTurnPassed(void) *(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE; *(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags; + BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers gBattleMainFunc = HandleTurnActionSelectionState; } diff --git a/src/battle_util.c b/src/battle_util.c index 1dd2c6b48..84016a554 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1432,7 +1432,7 @@ u8 DoFieldEndTurnEffects(void) gBattlescriptCurrInstr = BattleScript_DamagingWeatherContinues; } - gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES; // B_ANIM_SNOW_CONTINUES; // TODO: Animation + gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES; // TODO: Animation B_ANIM_SNOW_CONTINUES; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SNOW; BattleScriptExecute(gBattlescriptCurrInstr); effect++; @@ -1453,8 +1453,7 @@ u8 DoFieldEndTurnEffects(void) } else { - // TODO: Dynamax - // ChooseDamageNonTypesString(gSideTimers[side].damageNonTypesType); + ChooseDamageNonTypesString(gSideTimers[side].damageNonTypesType); BattleScriptExecute(BattleScript_DamageNonTypesContinues); } } @@ -1769,9 +1768,7 @@ u8 DoBattlerEndTurnEffects(void) && !(gStatuses3[battler] & STATUS3_HEAL_BLOCK) && gBattleMons[battler].hp != 0) { - // TODO: Dynamax - // gBattleMoveDamage = GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16); - gBattleMoveDamage = GetDrainedBigRootHp(battler, gBattleMons[battler].maxHP / 16); + gBattleMoveDamage = GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16); BattleScriptExecute(BattleScript_IngrainTurnHeal); effect++; } @@ -1783,9 +1780,7 @@ u8 DoBattlerEndTurnEffects(void) && !(gStatuses3[battler] & STATUS3_HEAL_BLOCK) && gBattleMons[battler].hp != 0) { - // TODO: Dynamax - // gBattleMoveDamage = GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16); - gBattleMoveDamage = GetDrainedBigRootHp(battler, gBattleMons[battler].maxHP / 16); + gBattleMoveDamage = GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16); BattleScriptExecute(BattleScript_AquaRingHeal); effect++; } @@ -1819,9 +1814,7 @@ u8 DoBattlerEndTurnEffects(void) MAGIC_GUARD_CHECK; gBattlerTarget = gStatuses3[battler] & STATUS3_LEECHSEED_BATTLER; // Notice gBattlerTarget is actually the HP receiver. - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; - gBattleMoveDamage = gBattleMons[battler].maxHP / 8; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; gBattleScripting.animArg1 = gBattlerTarget; @@ -1841,9 +1834,7 @@ u8 DoBattlerEndTurnEffects(void) { if (!BATTLER_MAX_HP(battler) && !(gStatuses3[battler] & STATUS3_HEAL_BLOCK)) { - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; - gBattleMoveDamage = gBattleMons[battler].maxHP / 8; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; gBattleMoveDamage *= -1; @@ -1853,9 +1844,7 @@ u8 DoBattlerEndTurnEffects(void) } else { - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; - gBattleMoveDamage = gBattleMons[battler].maxHP / 8; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; BattleScriptExecute(BattleScript_PoisonTurnDmg); @@ -1874,9 +1863,7 @@ u8 DoBattlerEndTurnEffects(void) { if (!BATTLER_MAX_HP(battler) && !(gStatuses3[battler] & STATUS3_HEAL_BLOCK)) { - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; - gBattleMoveDamage = gBattleMons[battler].maxHP / 8; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; gBattleMoveDamage *= -1; @@ -1886,9 +1873,7 @@ u8 DoBattlerEndTurnEffects(void) } else { - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 16; - gBattleMoveDamage = gBattleMons[battler].maxHP / 16; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 16; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; if ((gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_TURN(15)) // not 16 turns @@ -1905,9 +1890,7 @@ u8 DoBattlerEndTurnEffects(void) && gBattleMons[battler].hp != 0) { MAGIC_GUARD_CHECK; - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); - gBattleMoveDamage = gBattleMons[battler].maxHP / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); if (ability == ABILITY_HEATPROOF) { if (gBattleMoveDamage > (gBattleMoveDamage / 2) + 1) // Record ability if the burn takes less damage than it normally would. @@ -1926,9 +1909,7 @@ u8 DoBattlerEndTurnEffects(void) && gBattleMons[battler].hp != 0) { MAGIC_GUARD_CHECK; - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); - gBattleMoveDamage = gBattleMons[battler].maxHP / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; BattleScriptExecute(BattleScript_FrostbiteTurnDmg); @@ -1945,9 +1926,7 @@ u8 DoBattlerEndTurnEffects(void) // persist even after the affected Pokémon has been awakened by Shed Skin. if (gBattleMons[battler].status1 & STATUS1_SLEEP) { - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 4; - gBattleMoveDamage = gBattleMons[battler].maxHP / 4; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 4; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; BattleScriptExecute(BattleScript_NightmareTurnDmg); @@ -1965,9 +1944,7 @@ u8 DoBattlerEndTurnEffects(void) && gBattleMons[battler].hp != 0) { MAGIC_GUARD_CHECK; - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 4; - gBattleMoveDamage = gBattleMons[battler].maxHP / 4; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 4; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; BattleScriptExecute(BattleScript_CurseTurnDmg); @@ -1987,17 +1964,9 @@ u8 DoBattlerEndTurnEffects(void) PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[battler]); gBattlescriptCurrInstr = BattleScript_WrapTurnDmg; if (GetBattlerHoldEffect(gBattleStruct->wrappedBy[battler], TRUE) == HOLD_EFFECT_BINDING_BAND) - { - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); - gBattleMoveDamage = gBattleMons[battler].maxHP / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); - } + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); else - { - // TODO: Dynamax - // gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); - gBattleMoveDamage = gBattleMons[battler].maxHP / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); - } + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; @@ -2329,15 +2298,14 @@ u8 DoBattlerEndTurnEffects(void) gBattleStruct->turnEffectsTracker++; break; case ENDTURN_DYNAMAX: - // TODO: Dynamax - // if (IsDynamaxed(battler) - // && --gBattleStruct->dynamax.dynamaxTurns[battler] == 0) - // { - // gBattleScripting.battler = battler; - // UndoDynamax(battler); - // BattleScriptExecute(BattleScript_DynamaxEnds); - // effect++; - // } + if (IsDynamaxed(battler) + && --gBattleStruct->dynamax.dynamaxTurns[battler] == 0) + { + gBattleScripting.battler = battler; + UndoDynamax(battler); + BattleScriptExecute(BattleScript_DynamaxEnds); + effect++; + } gBattleStruct->turnEffectsTracker++; break; case ENDTURN_SEA_OF_FIRE_DAMAGE: @@ -2494,8 +2462,26 @@ bool8 HandleFaintedMonActions(void) gBattleStruct->faintedActionsState = 3; else gBattleStruct->faintedActionsState = 1; + // Don't switch mons until all pokemon performed their actions or the battle's over. + if (B_FAINT_SWITCH_IN >= GEN_4 + && gBattleOutcome == 0 + && !NoAliveMonsForEitherParty() + && gCurrentTurnActionNumber != gBattlersCount) + { + gAbsentBattlerFlags |= gBitTable[gBattlerFainted]; + if (gBattleStruct->faintedActionsState != 1) + return FALSE; + } break; case 3: + // Don't switch mons until all pokemon performed their actions or the battle's over. + if (B_FAINT_SWITCH_IN >= GEN_4 + && gBattleOutcome == 0 + && !NoAliveMonsForEitherParty() + && gCurrentTurnActionNumber != gBattlersCount) + { + return FALSE; + } gBattleStruct->faintedActionsBattlerId = 0; gBattleStruct->faintedActionsState++; // fall through @@ -2520,10 +2506,7 @@ bool8 HandleFaintedMonActions(void) gBattleStruct->faintedActionsState = 4; break; case 6: - if (AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE1, 0, 0, 0, 0) - || AbilityBattleEffects(ABILITYEFFECT_TRACE, 0, 0, 0, 0) - || ItemBattleEffects(ITEMEFFECT_NORMAL, 0, TRUE) - || AbilityBattleEffects(ABILITYEFFECT_FORECAST, 0, 0, 0, 0)) + if (ItemBattleEffects(ITEMEFFECT_NORMAL, 0, TRUE)) return TRUE; gBattleStruct->faintedActionsState++; break; From b00c2d08abaabf2946e93d6b32ea150b0fd9acaa Mon Sep 17 00:00:00 2001 From: cawtds Date: Sat, 11 May 2024 17:49:45 +0200 Subject: [PATCH 07/11] small updates, first idea for loreleis team --- src/battle_main.c | 36 +++++++++++++++++++---- src/battle_script_commands.c | 17 +++++------ src/data.c | 1 + src/data/trainer_parties.h | 57 ++++++++++++++++++++++++------------ 4 files changed, 77 insertions(+), 34 deletions(-) diff --git a/src/battle_main.c b/src/battle_main.c index 0049fedd4..eef62a20b 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3901,13 +3901,12 @@ static void HandleTurnActionSelectionState(void) else if (gBattleResources->bufferB[battler][2] & RET_DYNAMAX) gBattleStruct->dynamax.toDynamax |= gBitTable[battler]; - // TODO: Dynamax // Max Move check - // if (ShouldUseMaxMove(battler, gChosenMoveByBattler[battler])) - // { - // gBattleStruct->dynamax.baseMove[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; - // gBattleStruct->dynamax.usingMaxMove[battler] = TRUE; - // } + if (ShouldUseMaxMove(battler, gChosenMoveByBattler[battler])) + { + gBattleStruct->dynamax.baseMove[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; + gBattleStruct->dynamax.usingMaxMove[battler] = TRUE; + } gBattleCommunication[battler]++; } @@ -3999,9 +3998,34 @@ static void HandleTurnActionSelectionState(void) break; } } + // Check if everyone chose actions. if (gBattleCommunication[ACTIONS_CONFIRMED_COUNT] == gBattlersCount) + { + if (WILD_DOUBLE_BATTLE + && gBattleStruct->throwingPokeBall + && gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)] != B_ACTION_NOTHING_FAINTED) + { + // if we choose to throw a ball with our second mon, skip the action of the first + // (if we have chosen throw ball with first, second's is already skipped) + // if throwing a ball in a wild battle with an in-game partner, skip partner's turn when throwing a ball + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)] = B_ACTION_NOTHING_FAINTED; + else + gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] = B_ACTION_NOTHING_FAINTED; + } + gBattleMainFunc = SetActionsAndBattlersTurnOrder; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + for (i = 0; i < gBattlersCount; i++) + { + if (gChosenActionByBattler[i] == B_ACTION_SWITCH) + SwitchPartyOrderInGameMulti(i, *(gBattleStruct->monToSwitchIntoId + i)); + } + } + } } static void UpdateBattlerPartyOrdersOnSwitch(u32 battler) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9e73cbbd3..4809c3cdc 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1400,14 +1400,13 @@ static void Cmd_attackcanceler(void) } // Z-moves and Max Moves bypass protection, but deal reduced damage (factored in AccumulateOtherModifiers) - // TODO: Z-Moves and Dynamax - // if ((gBattleStruct->zmove.active || IsMaxMove(gCurrentMove)) - // && IS_BATTLER_PROTECTED(gBattlerTarget)) - // { - // BattleScriptPush(cmd->nextInstr); - // gBattlescriptCurrInstr = BattleScript_CouldntFullyProtect; - // return; - // } + if ((gBattleStruct->zmove.active || IsMaxMove(gCurrentMove)) + && IS_BATTLER_PROTECTED(gBattlerTarget)) + { + BattleScriptPush(cmd->nextInstr); + gBattlescriptCurrInstr = BattleScript_CouldntFullyProtect; + return; + } for (i = 0; i < gBattlersCount; i++) { @@ -6373,7 +6372,7 @@ static void Cmd_getswitchedmondata(void) u32 battler = GetBattlerForBattleScript(cmd->battler); if (gBattleControllerExecFlags) return; - + gBattlerPartyIndexes[battler] = gBattleStruct->monToSwitchIntoId[battler]; BtlController_EmitGetMonData(battler, BUFFER_A, REQUEST_ALL_BATTLE, gBitTable[gBattlerPartyIndexes[battler]]); MarkBattlerForControllerExec(battler); diff --git a/src/data.c b/src/data.c index f727b57db..63af889b4 100644 --- a/src/data.c +++ b/src/data.c @@ -3,6 +3,7 @@ #include "battle.h" #include "data.h" #include "graphics.h" +#include "constants/abilities.h" #include "constants/items.h" #include "constants/moves.h" #include "constants/battle_ai.h" diff --git a/src/data/trainer_parties.h b/src/data/trainer_parties.h index 0bf93234d..2397aeb7f 100644 --- a/src/data/trainer_parties.h +++ b/src/data/trainer_parties.h @@ -4799,39 +4799,58 @@ static const struct TrainerMon sParty_CooltrainerJulie[] = { static const struct TrainerMon sParty_EliteFourLorelei[] = { { - .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 52, - .species = SPECIES_DEWGONG, - .heldItem = ITEM_NONE, - .moves = {MOVE_ICE_BEAM, MOVE_SURF, MOVE_HAIL, MOVE_SAFEGUARD}, + .species = SPECIES_NINETALES_ALOLAN, + .ability = ABILITY_SNOW_WARNING, + .heldItem = ITEM_ICY_ROCK, + .nature = NATURE_TIMID, + .moves = {MOVE_BLIZZARD, MOVE_MOONBLAST, MOVE_AURORA_VEIL, MOVE_CHILLING_WATER}, }, { - .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 51, - .species = SPECIES_CLOYSTER, - .heldItem = ITEM_NONE, - .moves = {MOVE_SPIKES, MOVE_PROTECT, MOVE_HAIL, MOVE_DIVE}, + .species = SPECIES_GLACEON, + .ability = ABILITY_SNOW_CLOAK, + .heldItem = ITEM_CHOICE_SPECS, + .nature = NATURE_TIMID, + .moves = {MOVE_ICE_BEAM, MOVE_SHADOW_BALL, MOVE_BLIZZARD, MOVE_ALLURING_VOICE}, }, { - .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 52, - .species = SPECIES_SLOWBRO, - .heldItem = ITEM_NONE, - .moves = {MOVE_ICE_BEAM, MOVE_SURF, MOVE_AMNESIA, MOVE_YAWN}, + .species = SPECIES_CLOYSTER, + .ability = ABILITY_SKILL_LINK, + .heldItem = ITEM_FOCUS_SASH, + .nature = NATURE_JOLLY, + .moves = {MOVE_SHELL_SMASH, MOVE_ICICLE_SPEAR, MOVE_ICE_SHARD, MOVE_SPIKES}, }, { - .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 54, - .species = SPECIES_JYNX, - .heldItem = ITEM_NONE, - .moves = {MOVE_ICE_PUNCH, MOVE_DOUBLE_SLAP, MOVE_LOVELY_KISS, MOVE_ATTRACT}, + .species = SPECIES_MR_RIME, + .ability = ABILITY_ICE_BODY, + .heldItem = ITEM_LIGHT_CLAY, + .nature = NATURE_MODEST, + .moves = {MOVE_HAIL, MOVE_PSYCHIC, MOVE_FREEZE_DRY, MOVE_ICE_BEAM}, }, { - .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), + .lvl = 54, + .species = SPECIES_ARTICUNO, + .ability = ABILITY_SNOW_CLOAK, + .heldItem = ITEM_HEAVY_DUTY_BOOTS, + .nature = NATURE_TIMID, + .moves = {MOVE_BLIZZARD, MOVE_ROOST, MOVE_EXTRASENSORY, MOVE_ICE_BEAM}, + }, + { + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .lvl = 54, .species = SPECIES_LAPRAS, - .heldItem = ITEM_SITRUS_BERRY, - .moves = {MOVE_CONFUSE_RAY, MOVE_ICE_BEAM, MOVE_SURF, MOVE_BODY_SLAM}, + .ability = ABILITY_SHELL_ARMOR, + .heldItem = ITEM_LEFTOVERS, + .nature = NATURE_CALM, + .moves = {MOVE_SURF, MOVE_ICE_BEAM, MOVE_CALM_MIND, MOVE_PERISH_SONG}, }, }; From 5b856c5803d00f0c4cab2ef9c77ca9c50fcfc2a3 Mon Sep 17 00:00:00 2001 From: cawtds Date: Sat, 11 May 2024 17:53:50 +0200 Subject: [PATCH 08/11] revert lorelei team changes --- src/data/trainer_parties.h | 61 +++++++++++++------------------------- 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/src/data/trainer_parties.h b/src/data/trainer_parties.h index 2397aeb7f..0bf93234d 100644 --- a/src/data/trainer_parties.h +++ b/src/data/trainer_parties.h @@ -4799,58 +4799,39 @@ static const struct TrainerMon sParty_CooltrainerJulie[] = { static const struct TrainerMon sParty_EliteFourLorelei[] = { { - .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 52, - .species = SPECIES_NINETALES_ALOLAN, - .ability = ABILITY_SNOW_WARNING, - .heldItem = ITEM_ICY_ROCK, - .nature = NATURE_TIMID, - .moves = {MOVE_BLIZZARD, MOVE_MOONBLAST, MOVE_AURORA_VEIL, MOVE_CHILLING_WATER}, + .species = SPECIES_DEWGONG, + .heldItem = ITEM_NONE, + .moves = {MOVE_ICE_BEAM, MOVE_SURF, MOVE_HAIL, MOVE_SAFEGUARD}, }, { - .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 51, - .species = SPECIES_GLACEON, - .ability = ABILITY_SNOW_CLOAK, - .heldItem = ITEM_CHOICE_SPECS, - .nature = NATURE_TIMID, - .moves = {MOVE_ICE_BEAM, MOVE_SHADOW_BALL, MOVE_BLIZZARD, MOVE_ALLURING_VOICE}, - }, - { - .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), - .lvl = 52, .species = SPECIES_CLOYSTER, - .ability = ABILITY_SKILL_LINK, - .heldItem = ITEM_FOCUS_SASH, - .nature = NATURE_JOLLY, - .moves = {MOVE_SHELL_SMASH, MOVE_ICICLE_SPEAR, MOVE_ICE_SHARD, MOVE_SPIKES}, + .heldItem = ITEM_NONE, + .moves = {MOVE_SPIKES, MOVE_PROTECT, MOVE_HAIL, MOVE_DIVE}, }, { - .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), + .lvl = 52, + .species = SPECIES_SLOWBRO, + .heldItem = ITEM_NONE, + .moves = {MOVE_ICE_BEAM, MOVE_SURF, MOVE_AMNESIA, MOVE_YAWN}, + }, + { + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 54, - .species = SPECIES_MR_RIME, - .ability = ABILITY_ICE_BODY, - .heldItem = ITEM_LIGHT_CLAY, - .nature = NATURE_MODEST, - .moves = {MOVE_HAIL, MOVE_PSYCHIC, MOVE_FREEZE_DRY, MOVE_ICE_BEAM}, + .species = SPECIES_JYNX, + .heldItem = ITEM_NONE, + .moves = {MOVE_ICE_PUNCH, MOVE_DOUBLE_SLAP, MOVE_LOVELY_KISS, MOVE_ATTRACT}, }, { - .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), - .lvl = 54, - .species = SPECIES_ARTICUNO, - .ability = ABILITY_SNOW_CLOAK, - .heldItem = ITEM_HEAVY_DUTY_BOOTS, - .nature = NATURE_TIMID, - .moves = {MOVE_BLIZZARD, MOVE_ROOST, MOVE_EXTRASENSORY, MOVE_ICE_BEAM}, - }, - { - .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), + .iv = TRAINER_PARTY_IVS(30, 30, 30, 30, 30, 30), .lvl = 54, .species = SPECIES_LAPRAS, - .ability = ABILITY_SHELL_ARMOR, - .heldItem = ITEM_LEFTOVERS, - .nature = NATURE_CALM, - .moves = {MOVE_SURF, MOVE_ICE_BEAM, MOVE_CALM_MIND, MOVE_PERISH_SONG}, + .heldItem = ITEM_SITRUS_BERRY, + .moves = {MOVE_CONFUSE_RAY, MOVE_ICE_BEAM, MOVE_SURF, MOVE_BODY_SLAM}, }, }; From a1b4f04468e3106b061ed26bdaaa78737a5758cb Mon Sep 17 00:00:00 2001 From: cawtds Date: Sun, 12 May 2024 00:07:10 +0200 Subject: [PATCH 09/11] fixed dive and lure ball, more battle_main updates --- include/wild_encounter.h | 2 + src/battle_main.c | 334 ++++++++++++++++++---------------- src/battle_script_commands.c | 27 ++- src/data/wild_encounters.json | 40 ++-- src/wild_encounter.c | 6 +- 5 files changed, 217 insertions(+), 192 deletions(-) diff --git a/include/wild_encounter.h b/include/wild_encounter.h index b73010306..066366dc7 100644 --- a/include/wild_encounter.h +++ b/include/wild_encounter.h @@ -34,6 +34,8 @@ struct WildPokemonHeader }; extern const struct WildPokemonHeader gWildMonHeaders[]; +extern bool8 gIsFishingEncounter; +extern bool8 gIsSurfingEncounter; void DisableWildEncounters(bool8 disabled); bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetaTileBehavior); diff --git a/src/battle_main.c b/src/battle_main.c index eef62a20b..cc01d5f2a 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -34,6 +34,7 @@ #include "task.h" #include "trig.h" #include "vs_seeker.h" +#include "wild_encounter.h" #include "util.h" #include "constants/abilities.h" #include "constants/battle_move_effects.h" @@ -222,6 +223,7 @@ EWRAM_DATA u8 gLastUsedBall = 0; EWRAM_DATA u16 gLastThrownBall = 0; EWRAM_DATA u16 gBallToDisplay = 0; EWRAM_DATA struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA static u8 sTriedEvolving = 0; void (*gPreBattleCallback1)(void); void (*gBattleMainFunc)(void); @@ -4052,6 +4054,133 @@ void SwapTurnOrder(u8 id1, u8 id2) SWAP(gBattlerByTurnOrder[id1], gBattlerByTurnOrder[id2], temp); } +// For AI, so it doesn't 'cheat' by knowing player's ability +u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect) +{ + u32 speed = gBattleMons[battler].speed; + u32 highestStat = GetHighestStatId(battler); + + // weather abilities + if (WEATHER_HAS_EFFECT) + { + if (ability == ABILITY_SWIFT_SWIM && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && gBattleWeather & B_WEATHER_RAIN) + speed *= 2; + else if (ability == ABILITY_CHLOROPHYLL && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && gBattleWeather & B_WEATHER_SUN) + speed *= 2; + else if (ability == ABILITY_SAND_RUSH && gBattleWeather & B_WEATHER_SANDSTORM) + speed *= 2; + else if (ability == ABILITY_SLUSH_RUSH && (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) + speed *= 2; + } + + // other abilities + if (ability == ABILITY_QUICK_FEET && gBattleMons[battler].status1 & STATUS1_ANY) + speed = (speed * 150) / 100; + else if (ability == ABILITY_SURGE_SURFER && gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + speed *= 2; + else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0) + speed /= 2; + else if (ability == ABILITY_PROTOSYNTHESIS && gBattleWeather & B_WEATHER_SUN && highestStat == STAT_SPEED) + speed = (speed * 150) / 100; + else if (ability == ABILITY_QUARK_DRIVE && gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && highestStat == STAT_SPEED) + speed = (speed * 150) / 100; + + // stat stages + speed *= gStatStageRatios[gBattleMons[battler].statStages[STAT_SPEED]][0]; + speed /= gStatStageRatios[gBattleMons[battler].statStages[STAT_SPEED]][1]; + + // player's badge boost + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_BATTLE_TOWER)) + && ShouldGetStatBadgeBoost(FLAG_BADGE03_GET, battler) + && GetBattlerSide(battler) == B_SIDE_PLAYER) + { + speed = (speed * 110) / 100; + } + + // item effects + if (holdEffect == HOLD_EFFECT_MACHO_BRACE || holdEffect == HOLD_EFFECT_POWER_ITEM) + speed /= 2; + else if (holdEffect == HOLD_EFFECT_IRON_BALL) + speed /= 2; + else if (holdEffect == HOLD_EFFECT_CHOICE_SCARF /*&& !IsDynamaxed(battler)*/) // TODO: Dynamax + speed = (speed * 150) / 100; + else if (holdEffect == HOLD_EFFECT_QUICK_POWDER && gBattleMons[battler].species == SPECIES_DITTO && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) + speed *= 2; + + // various effects + if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TAILWIND) + speed *= 2; + if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_UNBURDEN) + speed *= 2; + + // paralysis drop + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS && ability != ABILITY_QUICK_FEET) + speed /= B_PARALYSIS_SPEED >= GEN_7 ? 2 : 4; + + if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SWAMP) + speed /= 4; + + return speed; +} + +u32 GetBattlerTotalSpeedStat(u32 battler) +{ + u32 ability = GetBattlerAbility(battler); + u32 holdEffect = GetBattlerHoldEffect(battler, TRUE); + return GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect); +} + +s8 GetChosenMovePriority(u32 battler) +{ + u16 move; + + gProtectStructs[battler].pranksterElevated = 0; + if (gProtectStructs[battler].noValidMoves) + move = MOVE_STRUGGLE; + else + move = gBattleMons[battler].moves[*(gBattleStruct->chosenMovePositions + battler)]; + + return GetMovePriority(battler, move); +} + +s8 GetMovePriority(u32 battler, u16 move) +{ + s8 priority; + u16 ability = GetBattlerAbility(battler); + + if (gBattleStruct->zmove.toBeUsed[battler] && gMovesInfo[move].power != 0) + move = gBattleStruct->zmove.toBeUsed[battler]; + + priority = gMovesInfo[move].priority; + + // Max Guard check + if (gBattleStruct->dynamax.usingMaxMove[battler] && gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS) + return gMovesInfo[MOVE_MAX_GUARD].priority; + + if (ability == ABILITY_GALE_WINGS + && (B_GALE_WINGS < GEN_7 || BATTLER_MAX_HP(battler)) + && gMovesInfo[move].type == TYPE_FLYING) + { + priority++; + } + else if (ability == ABILITY_PRANKSTER && IS_MOVE_STATUS(move)) + { + gProtectStructs[battler].pranksterElevated = 1; + priority++; + } + else if (gMovesInfo[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler)) + { + priority++; + } + else if (ability == ABILITY_TRIAGE && IsHealingMove(move)) + priority += 3; + + if (gProtectStructs[battler].quash) + priority = -8; + + return priority; +} + // Function for AI with variables provided as arguments to speed the computation time s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2, u32 holdEffectBattler1, u32 holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2) @@ -4320,7 +4449,7 @@ static bool32 TryDoGimmicksBeforeMoves(void) gBattlerAttacker = order[i]; gBattleScripting.battler = gBattlerAttacker; gBattleStruct->dynamax.toDynamax &= ~(gBitTable[gBattlerAttacker]); - // PrepareBattlerForDynamax(gBattlerAttacker); // TODO: Dynamax + PrepareBattlerForDynamax(gBattlerAttacker); BattleScriptExecute(BattleScript_DynamaxBegins); return TRUE; } @@ -4544,10 +4673,11 @@ static void HandleEndTurn_BattleWon(void) gCurrentActionFuncId = 0; if (gBattleTypeFlags & BATTLE_TYPE_LINK) { + gSpecialVar_Result = gBattleOutcome; gBattleTextBuff1[0] = gBattleOutcome; gBattlerAttacker = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost; - gBattleOutcome &= ~(B_OUTCOME_LINK_BATTLE_RAN); + gBattleOutcome &= ~B_OUTCOME_LINK_BATTLE_RAN; } else if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_BATTLE_TOWER)) { @@ -4590,7 +4720,7 @@ static void HandleEndTurn_BattleLost(void) gBattleTextBuff1[0] = gBattleOutcome; gBattlerAttacker = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost; - gBattleOutcome &= ~(B_OUTCOME_LINK_BATTLE_RAN); + gBattleOutcome &= ~B_OUTCOME_LINK_BATTLE_RAN; } else { @@ -4721,18 +4851,35 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) { if (!gPaletteFade.active) { + gIsFishingEncounter = FALSE; + gIsSurfingEncounter = FALSE; ResetSpriteData(); - if (gLeveledUpInBattle == 0 || gBattleOutcome != B_OUTCOME_WON) - gBattleMainFunc = ReturnFromBattleToOverworld; - else - gBattleMainFunc = TryEvolvePokemon; - FreeAllWindowBuffers(); - if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_FIRST_BATTLE + | BATTLE_TYPE_SAFARI + | BATTLE_TYPE_BATTLE_TOWER + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_OLD_MAN_TUTORIAL + | BATTLE_TYPE_POKEDUDE)) + && (B_EVOLUTION_AFTER_WHITEOUT >= GEN_6 + || gBattleOutcome == B_OUTCOME_WON + || gBattleOutcome == B_OUTCOME_CAUGHT)) { - FreeMonSpritesGfx(); - FreeBattleSpritesData(); - FreeBattleResources(); + gBattleMainFunc = TryEvolvePokemon; } + else + { + gBattleMainFunc = ReturnFromBattleToOverworld; + return; + } + } + + FreeAllWindowBuffers(); + if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) + { + FreeMonSpritesGfx(); + FreeBattleSpritesData(); + FreeBattleResources(); } } @@ -4740,28 +4887,30 @@ static void TryEvolvePokemon(void) { s32 i; - while (gLeveledUpInBattle != 0) + for (i = 0; i < PARTY_SIZE; i++) { - for (i = 0; i < PARTY_SIZE; i++) + if (!(sTriedEvolving & gBitTable[i])) { - if (gLeveledUpInBattle & gBitTable[i]) + u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, NULL); + sTriedEvolving |= gBitTable[i]; + + if (species == SPECIES_NONE && (gLeveledUpInBattle & gBitTable[i])) + { + gLeveledUpInBattle &= ~(gBitTable[i]); + species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_NORMAL, gLeveledUpInBattle, NULL); + } + + if (species != SPECIES_NONE) { - u16 species; - u8 levelUpBits = gLeveledUpInBattle; - - levelUpBits &= ~(gBitTable[i]); - gLeveledUpInBattle = levelUpBits; - - species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_NORMAL, levelUpBits, NULL); - if (species != SPECIES_NONE) - { - gBattleMainFunc = WaitForEvoSceneToFinish; - EvolutionScene(&gPlayerParty[i], species, 0x81, i); - return; - } + FreeAllWindowBuffers(); + gBattleMainFunc = WaitForEvoSceneToFinish; + EvolutionScene(&gPlayerParty[i], species, TRUE, i); + return; } } } + sTriedEvolving = 0; + gLeveledUpInBattle = 0; gBattleMainFunc = ReturnFromBattleToOverworld; } @@ -4998,135 +5147,6 @@ static void HandleAction_ActionFinished(void) } } -s8 GetMovePriority(u32 battler, u16 move) -{ - s8 priority; - u16 ability = GetBattlerAbility(battler); - - // TODO: Z-Moves - // if (gBattleStruct->zmove.toBeUsed[battler] && gMovesInfo[move].power != 0) - // move = gBattleStruct->zmove.toBeUsed[battler]; - - priority = gMovesInfo[move].priority; - - // Max Guard check - // TODO: Dynamax - // if (gBattleStruct->dynamax.usingMaxMove[battler] && gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS) - // return gMovesInfo[MOVE_MAX_GUARD].priority; - - if (ability == ABILITY_GALE_WINGS - && (B_GALE_WINGS < GEN_7 || BATTLER_MAX_HP(battler)) - && gMovesInfo[move].type == TYPE_FLYING) - { - priority++; - } - else if (ability == ABILITY_PRANKSTER && IS_MOVE_STATUS(move)) - { - gProtectStructs[battler].pranksterElevated = 1; - priority++; - } - else if (gMovesInfo[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler)) - { - priority++; - } - else if (ability == ABILITY_TRIAGE && IsHealingMove(move)) - priority += 3; - - if (gProtectStructs[battler].quash) - priority = -8; - - return priority; -} - -s8 GetChosenMovePriority(u32 battler) -{ - u16 move; - - gProtectStructs[battler].pranksterElevated = 0; - if (gProtectStructs[battler].noValidMoves) - move = MOVE_STRUGGLE; - else - move = gBattleMons[battler].moves[*(gBattleStruct->chosenMovePositions + battler)]; - - return GetMovePriority(battler, move); -} - -// For AI, so it doesn't 'cheat' by knowing player's ability -u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect) -{ - u32 speed = gBattleMons[battler].speed; - u32 highestStat = GetHighestStatId(battler); - - // weather abilities - if (WEATHER_HAS_EFFECT) - { - if (ability == ABILITY_SWIFT_SWIM && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && gBattleWeather & B_WEATHER_RAIN) - speed *= 2; - else if (ability == ABILITY_CHLOROPHYLL && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && gBattleWeather & B_WEATHER_SUN) - speed *= 2; - else if (ability == ABILITY_SAND_RUSH && gBattleWeather & B_WEATHER_SANDSTORM) - speed *= 2; - else if (ability == ABILITY_SLUSH_RUSH && (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) - speed *= 2; - } - - // other abilities - if (ability == ABILITY_QUICK_FEET && gBattleMons[battler].status1 & STATUS1_ANY) - speed = (speed * 150) / 100; - else if (ability == ABILITY_SURGE_SURFER && gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) - speed *= 2; - else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0) - speed /= 2; - else if (ability == ABILITY_PROTOSYNTHESIS && gBattleWeather & B_WEATHER_SUN && highestStat == STAT_SPEED) - speed = (speed * 150) / 100; - else if (ability == ABILITY_QUARK_DRIVE && gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && highestStat == STAT_SPEED) - speed = (speed * 150) / 100; - - // stat stages - speed *= gStatStageRatios[gBattleMons[battler].statStages[STAT_SPEED]][0]; - speed /= gStatStageRatios[gBattleMons[battler].statStages[STAT_SPEED]][1]; - - // player's badge boost - if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_BATTLE_TOWER)) - && ShouldGetStatBadgeBoost(FLAG_BADGE03_GET, battler) - && GetBattlerSide(battler) == B_SIDE_PLAYER) - { - speed = (speed * 110) / 100; - } - - // item effects - if (holdEffect == HOLD_EFFECT_MACHO_BRACE || holdEffect == HOLD_EFFECT_POWER_ITEM) - speed /= 2; - else if (holdEffect == HOLD_EFFECT_IRON_BALL) - speed /= 2; - else if (holdEffect == HOLD_EFFECT_CHOICE_SCARF /*&& !IsDynamaxed(battler)*/) // TODO: Dynamax - speed = (speed * 150) / 100; - else if (holdEffect == HOLD_EFFECT_QUICK_POWDER && gBattleMons[battler].species == SPECIES_DITTO && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) - speed *= 2; - - // various effects - if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TAILWIND) - speed *= 2; - if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_UNBURDEN) - speed *= 2; - - // paralysis drop - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS && ability != ABILITY_QUICK_FEET) - speed /= B_PARALYSIS_SPEED >= GEN_7 ? 2 : 4; - - if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SWAMP) - speed /= 4; - - return speed; -} - -u32 GetBattlerTotalSpeedStat(u32 battler) -{ - u32 ability = GetBattlerAbility(battler); - u32 holdEffect = GetBattlerHoldEffect(battler, TRUE); - return GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect); -} - void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) { u32 moveType, ateType, attackerAbility; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 4809c3cdc..de0a85bba 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -29,6 +29,7 @@ #include "battle_controllers.h" #include "battle_interface.h" #include "rtc.h" +#include "wild_encounter.h" #include "constants/battle_anim.h" #include "constants/battle_move_effects.h" #include "constants/battle_script_commands.h" @@ -15026,10 +15027,9 @@ static void Cmd_handleballthrow(void) ballMultiplier = B_NET_BALL_MODIFIER >= GEN_7 ? 350 : 300; break; case ITEM_DIVE_BALL: - // TODO: gIsFishingEncounter and gIsSurfingEncounter - // if (GetCurrentMapType() == MAP_TYPE_UNDERWATER - // || (B_DIVE_BALL_MODIFIER >= GEN_4 && (gIsFishingEncounter || gIsSurfingEncounter))) - // ballMultiplier = 350; + if (GetCurrentMapType() == MAP_TYPE_UNDERWATER + || (B_DIVE_BALL_MODIFIER >= GEN_4 && (gIsFishingEncounter || gIsSurfingEncounter))) + ballMultiplier = 350; break; case ITEM_NEST_BALL: if (B_NEST_BALL_MODIFIER >= GEN_6) @@ -15079,16 +15079,15 @@ static void Cmd_handleballthrow(void) ballMultiplier = 200; break; case ITEM_LURE_BALL: - // TODO: gIsFishingEncounter - // if (gIsFishingEncounter) - // { - // if (B_LURE_BALL_MODIFIER >= GEN_8) - // ballMultiplier = 400; - // else if (B_LURE_BALL_MODIFIER >= GEN_7) - // ballMultiplier = 500; - // else - // ballMultiplier = 300; - // } + if (gIsFishingEncounter) + { + if (B_LURE_BALL_MODIFIER >= GEN_8) + ballMultiplier = 400; + else if (B_LURE_BALL_MODIFIER >= GEN_7) + ballMultiplier = 500; + else + ballMultiplier = 300; + } break; case ITEM_MOON_BALL: { diff --git a/src/data/wild_encounters.json b/src/data/wild_encounters.json index 2f38921c6..bf26d82f7 100644 --- a/src/data/wild_encounters.json +++ b/src/data/wild_encounters.json @@ -8263,27 +8263,27 @@ { "min_level": 3, "max_level": 3, - "species": "SPECIES_CHARIZARD" + "species": "SPECIES_FARFETCHD_GALARIAN" }, { "min_level": 3, "max_level": 3, - "species": "SPECIES_CHARIZARD" + "species": "SPECIES_FARFETCHD_GALARIAN" }, { "min_level": 3, "max_level": 3, - "species": "SPECIES_CHARIZARD" + "species": "SPECIES_FARFETCHD_GALARIAN" }, { "min_level": 3, "max_level": 3, - "species": "SPECIES_CHARIZARD" + "species": "SPECIES_FARFETCHD_GALARIAN" }, { "min_level": 2, "max_level": 2, - "species": "SPECIES_CHARIZARD" + "species": "SPECIES_FARFETCHD_GALARIAN" }, { "min_level": 2, @@ -10499,29 +10499,29 @@ "encounter_rate": 21, "mons": [ { - "min_level": 6, - "max_level": 6, - "species": "SPECIES_PARAS" + "min_level": 14, + "max_level": 14, + "species": "SPECIES_MAGIKARP" }, { - "min_level": 6, - "max_level": 6, - "species": "SPECIES_PARAS" + "min_level": 14, + "max_level": 14, + "species": "SPECIES_MAGIKARP" }, { - "min_level": 6, - "max_level": 6, - "species": "SPECIES_PARAS" + "min_level": 14, + "max_level": 14, + "species": "SPECIES_MAGIKARP" }, { - "min_level": 6, - "max_level": 6, - "species": "SPECIES_PARAS" + "min_level": 14, + "max_level": 14, + "species": "SPECIES_MAGIKARP" }, { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_RATTATA" + "min_level": 14, + "max_level": 14, + "species": "SPECIES_MAGIKARP" }, { "min_level": 2, diff --git a/src/wild_encounter.c b/src/wild_encounter.c index df17d55ef..15d66cf8e 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -33,6 +33,8 @@ struct WildEncounterData static EWRAM_DATA struct WildEncounterData sWildEncounterData = {}; static EWRAM_DATA bool8 sWildEncountersDisabled = FALSE; +EWRAM_DATA bool8 gIsFishingEncounter = 0; +EWRAM_DATA bool8 gIsSurfingEncounter = 0; static bool8 UnlockedTanobyOrAreNotInTanoby(void); static u32 GenerateUnownPersonalityByLetter(u8 letter); @@ -428,7 +430,8 @@ bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetatileBehavior) else // try a regular surfing encounter { if (TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL) == TRUE) - { + { + gIsSurfingEncounter = TRUE; StartWildBattle(); return TRUE; } @@ -520,6 +523,7 @@ void FishingWildEncounter(u8 rod) { GenerateFishingEncounter(gWildMonHeaders[GetCurrentMapWildMonHeaderId()].fishingMonsInfo, rod); IncrementGameStat(GAME_STAT_FISHING_CAPTURES); + gIsFishingEncounter = TRUE; StartWildBattle(); } From 56d32c797d91bc06084f31cfa772571e6ce3514f Mon Sep 17 00:00:00 2001 From: cawtds Date: Sun, 12 May 2024 02:30:07 +0200 Subject: [PATCH 10/11] finished updating battle_main, removed unused functions/variables, fixed trainer money rewards --- data/maps/PewterCity_Gym/text.inc | 3 - include/battle_main.h | 1 - include/battle_message.h | 4 +- include/battle_util.h | 9 + include/constants/battle.h | 6 - src/battle_main.c | 691 ++++++++---------------------- src/battle_script_commands.c | 13 +- src/battle_util.c | 191 +++++++++ src/berry.c | 10 +- 9 files changed, 402 insertions(+), 526 deletions(-) diff --git a/data/maps/PewterCity_Gym/text.inc b/data/maps/PewterCity_Gym/text.inc index 706842927..9f6dc019d 100644 --- a/data/maps/PewterCity_Gym/text.inc +++ b/data/maps/PewterCity_Gym/text.inc @@ -14,9 +14,6 @@ PewterCity_Gym_Text_BrockIntro:: .string "Fine, then!\n" .string "Show me your best!{PLAY_BGM}{MUS_ENCOUNTER_GYM_LEADER}$" -@ NOTE: This defeat text actually causes a buffer overflow. It's too long for the gDisplayedStringBattle -@ buffer that it's put into, and it stomps all over the gBattleTextBuffs after, as well as the otherwise -@ unused array after that, sFlickerArray. Perhaps that's the reason why said array exists. PewterCity_Gym_Text_BrockDefeat:: .string "I took you for granted, and so\n" .string "I lost.\p" diff --git a/include/battle_main.h b/include/battle_main.h index f0b44bed0..bc421c943 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -54,7 +54,6 @@ extern const u8 gStatusConditionString_IceJpn[8]; extern const u8 gStatusConditionString_ConfusionJpn[8]; extern const u8 gStatusConditionString_LoveJpn[8]; extern const u8 *const gStatusConditionStringsTable[7][2]; -extern const struct TrainerMoney gTrainerMoneyTable[]; void CB2_InitBattle(void); void BattleMainCB2(void); diff --git a/include/battle_message.h b/include/battle_message.h index 0fc59b4ee..a251d46db 100644 --- a/include/battle_message.h +++ b/include/battle_message.h @@ -233,10 +233,10 @@ extern struct BattleMsgData *gBattleMsgDataPtr; #define TEXT_BUFF_ARRAY_COUNT 16 -extern u8 gDisplayedStringBattle[300]; +extern u8 gDisplayedStringBattle[550]; extern u8 gBattleTextBuff1[TEXT_BUFF_ARRAY_COUNT]; extern u8 gBattleTextBuff2[TEXT_BUFF_ARRAY_COUNT]; -extern u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT]; +extern u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT + 13]; extern const u8 *const gBattleStringsTable[]; extern const u8 *const gStatNamesTable[]; diff --git a/include/battle_util.h b/include/battle_util.h index 1795ebacb..f3b7e0e59 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -125,6 +125,15 @@ void HandleAction_Switch(void); void HandleAction_UseItem(void); bool8 TryRunFromBattle(u8 battler); void HandleAction_Run(void); +void HandleAction_WatchesCarefully(void); +void HandleAction_SafariZoneBallThrow(void); +void HandleAction_ThrowBait(void); +void HandleAction_ThrowRock(void); +void HandleAction_SafariZoneRun(void); +void HandleAction_OldManBallThrow(void); +void HandleAction_TryFinish(void); +void HandleAction_NothingIsFainted(void); +void HandleAction_ActionFinished(void); u8 GetBattlerForBattleScript(u8 caseId); bool32 IsBattlerMarkedForControllerExec(u32 battler); diff --git a/include/constants/battle.h b/include/constants/battle.h index 38c495315..b1f29bd7d 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -212,11 +212,6 @@ #define HITMARKER_FAINTED(battler) (gBitTable[battler] << 28) #define HITMARKER_FAINTED2(battler) ((1 << 28) << battler) #define HITMARKER_STRING_PRINTED (1 << 29) -// TODO: old hitmarkers for compatability, remove with new battle system -#define HITMARKER_SKIP_DMG_TRACK (1 << 30) -#define HITMARKER_IGNORE_ON_AIR (1 << 31) -#define HITMARKER_IGNORE_UNDERGROUND (1 << 0) -#define HITMARKER_IGNORE_UNDERWATER (1 << 1) // Per-side statuses that affect an entire party @@ -227,7 +222,6 @@ #define SIDE_STATUS_SAFEGUARD (1 << 5) #define SIDE_STATUS_FUTUREATTACK (1 << 6) #define SIDE_STATUS_MIST (1 << 8) -#define SIDE_STATUS_SPIKES_DAMAGED (1 << 9) // TODO: remove with new battle system // (1 << 9) previously was SIDE_STATUS_SPIKES_DAMAGED #define SIDE_STATUS_TAILWIND (1 << 10) #define SIDE_STATUS_AURORA_VEIL (1 << 11) diff --git a/src/battle_main.c b/src/battle_main.c index cc01d5f2a..d433eef9b 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -47,15 +47,6 @@ #include "constants/trainers.h" static void SpriteCB_UnusedDebugSprite(struct Sprite *sprite); -static void HandleAction_WatchesCarefully(void); -static void HandleAction_SafariZoneBallThrow(void); -static void HandleAction_ThrowBait(void); -static void HandleAction_ThrowRock(void); -static void HandleAction_SafariZoneRun(void); -static void HandleAction_OldManBallThrow(void); -static void HandleAction_TryFinish(void); -static void HandleAction_NothingIsFainted(void); -static void HandleAction_ActionFinished(void); static void HandleEndTurn_ContinueBattle(void); static void HandleEndTurn_BattleWon(void); static void HandleEndTurn_BattleLost(void); @@ -75,7 +66,6 @@ static void CB2_EndLinkBattle(void); static void EndLinkBattleInSteps(void); static void SpriteCB_MoveWildMonToRight(struct Sprite *sprite); static void SpriteCB_WildMonShowHealthbox(struct Sprite *sprite); -static void SpriteCB_Flicker(struct Sprite *sprite); static void SpriteCB_AnimFaintOpponent(struct Sprite *sprite); static void SpriteCB_BlinkVisible(struct Sprite *sprite); static void oac_poke_ally_(struct Sprite *sprite); @@ -112,16 +102,10 @@ EWRAM_DATA u16 gBattle_WIN0H = 0; EWRAM_DATA u16 gBattle_WIN0V = 0; EWRAM_DATA u16 gBattle_WIN1H = 0; EWRAM_DATA u16 gBattle_WIN1V = 0; -EWRAM_DATA u8 gDisplayedStringBattle[300] = {0}; +EWRAM_DATA u8 gDisplayedStringBattle[550] = {0}; // Increased in size to fit Brock's defeat text (PewterCity_Gym_Text_BrockDefeat) EWRAM_DATA u8 gBattleTextBuff1[TEXT_BUFF_ARRAY_COUNT] = {0}; EWRAM_DATA u8 gBattleTextBuff2[TEXT_BUFF_ARRAY_COUNT] = {0}; -EWRAM_DATA u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT] = {0}; -// The below array is never intentionally used. However, Brock's -// defeat text (PewterCity_Gym_Text_BrockDefeat) is too long -// for gDisplayedStringBattle and overflows into this array. If it -// is removed (and none of the buffers above are increased in size) -// it will instead overflow into useful data. -static EWRAM_DATA u32 sFlickerArray[25] = {0}; +EWRAM_DATA u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT + 13] = {0}; // expanded for stupidly long z move names EWRAM_DATA u32 gBattleTypeFlags = 0; EWRAM_DATA u8 gBattleTerrain = 0; EWRAM_DATA struct MultiPartnerMenuPokemon gMultiPartnerParty[MULTI_PARTY_SIZE] = {0}; @@ -597,225 +581,115 @@ const struct TrainerClass gTrainerClasses[TRAINER_CLASS_COUNT] = { TRAINER_CLASS(NONE, "{PKMN} TRAINER"), TRAINER_CLASS(PKMN_TRAINER_UNUSED, "{PKMN} TRAINER"), - TRAINER_CLASS(AQUA_LEADER, "AQUA LEADER"), - TRAINER_CLASS(TEAM_AQUA, "TEAM AQUA"), - TRAINER_CLASS(RS_AROMA_LADY, "AROMA LADY"), - TRAINER_CLASS(RS_RUIN_MANIAC, "RUIN MANIAC"), - TRAINER_CLASS(INTERVIEWER, "INTERVIEWER"), - TRAINER_CLASS(RS_TUBER_F, "TUBER"), - TRAINER_CLASS(RS_TUBER_M, "TUBER"), - TRAINER_CLASS(RS_COOLTRAINER, "COOLTRAINER"), - TRAINER_CLASS(HEX_MANIAC, "HEX MANIAC"), - TRAINER_CLASS(RS_LADY, "LADY"), - TRAINER_CLASS(RS_BEAUTY, "BEAUTY"), - TRAINER_CLASS(RICH_BOY, "RICH BOY"), - TRAINER_CLASS(RS_POKEMANIAC, "POKéMANIAC"), - TRAINER_CLASS(RS_SWIMMER_M, "SWIMMER♂"), - TRAINER_CLASS(RS_BLACK_BELT, "BLACK BELT"), - TRAINER_CLASS(GUITARIST, "GUITARIST"), - TRAINER_CLASS(KINDLER, "KINDLER"), - TRAINER_CLASS(RS_CAMPER, "CAMPER"), - TRAINER_CLASS(BUG_MANIAC, "BUG MANIAC"), - TRAINER_CLASS(RS_PSYCHIC, "PSYCHIC"), - TRAINER_CLASS(RS_GENTLEMAN, "GENTLEMAN"), - TRAINER_CLASS(RS_ELITE_FOUR, "ELITE FOUR"), - TRAINER_CLASS(RS_LEADER, "LEADER"), - TRAINER_CLASS(SCHOOL_KID, "SCHOOL KID"), - TRAINER_CLASS(SR_AND_JR, "SR. AND JR."), - TRAINER_CLASS(POKEFAN, "POKéFAN"), - TRAINER_CLASS(EXPERT, "EXPERT"), - TRAINER_CLASS(RS_YOUNGSTER, "YOUNGSTER"), - TRAINER_CLASS(RS_CHAMPION, "CHAMPION"), - TRAINER_CLASS(RS_FISHERMAN, "FISHERMAN"), - TRAINER_CLASS(TRIATHLETE, "TRIATHLETE"), - TRAINER_CLASS(DRAGON_TAMER, "DRAGON TAMER"), - TRAINER_CLASS(RS_BIRD_KEEPER, "BIRD KEEPER"), - TRAINER_CLASS(NINJA_BOY, "NINJA BOY"), - TRAINER_CLASS(BATTLE_GIRL, "BATTLE GIRL"), - TRAINER_CLASS(PARASOL_LADY, "PARASOL LADY"), - TRAINER_CLASS(RS_SWIMMER_F, "SWIMMER♀"), - TRAINER_CLASS(RS_PICNICKER, "PICNICKER"), - TRAINER_CLASS(RS_TWINS, "TWINS"), - TRAINER_CLASS(RS_SAILOR, "SAILOR"), + TRAINER_CLASS(AQUA_LEADER, "AQUA LEADER", 20), + TRAINER_CLASS(TEAM_AQUA, "TEAM AQUA", 5), + TRAINER_CLASS(RS_AROMA_LADY, "AROMA LADY", 10), + TRAINER_CLASS(RS_RUIN_MANIAC, "RUIN MANIAC", 15), + TRAINER_CLASS(INTERVIEWER, "INTERVIEWER", 12), + TRAINER_CLASS(RS_TUBER_F, "TUBER", 1), + TRAINER_CLASS(RS_TUBER_M, "TUBER", 1), + TRAINER_CLASS(RS_COOLTRAINER, "COOLTRAINER", 12), + TRAINER_CLASS(HEX_MANIAC, "HEX MANIAC", 6), + TRAINER_CLASS(RS_LADY, "LADY", 50), + TRAINER_CLASS(RS_BEAUTY, "BEAUTY", 20), + TRAINER_CLASS(RICH_BOY, "RICH BOY", 50), + TRAINER_CLASS(RS_POKEMANIAC, "POKéMANIAC", 15), + TRAINER_CLASS(RS_SWIMMER_M, "SWIMMER♂", 2), + TRAINER_CLASS(RS_BLACK_BELT, "BLACK BELT", 8), + TRAINER_CLASS(GUITARIST, "GUITARIST", 8), + TRAINER_CLASS(KINDLER, "KINDLER", 8), + TRAINER_CLASS(RS_CAMPER, "CAMPER", 4), + TRAINER_CLASS(BUG_MANIAC, "BUG MANIAC", 15), + TRAINER_CLASS(RS_PSYCHIC, "PSYCHIC", 6), + TRAINER_CLASS(RS_GENTLEMAN, "GENTLEMAN", 20), + TRAINER_CLASS(RS_ELITE_FOUR, "ELITE FOUR", 25), + TRAINER_CLASS(RS_LEADER, "LEADER", 25), + TRAINER_CLASS(SCHOOL_KID, "SCHOOL KID", 5), + TRAINER_CLASS(SR_AND_JR, "SR. AND JR.", 4), + TRAINER_CLASS(POKEFAN, "POKéFAN", 20), + TRAINER_CLASS(EXPERT, "EXPERT", 10), + TRAINER_CLASS(RS_YOUNGSTER, "YOUNGSTER", 4), + TRAINER_CLASS(RS_CHAMPION, "CHAMPION", 50), + TRAINER_CLASS(RS_FISHERMAN, "FISHERMAN", 10), + TRAINER_CLASS(TRIATHLETE, "TRIATHLETE", 10), + TRAINER_CLASS(DRAGON_TAMER, "DRAGON TAMER", 12), + TRAINER_CLASS(RS_BIRD_KEEPER, "BIRD KEEPER", 8), + TRAINER_CLASS(NINJA_BOY, "NINJA BOY", 3), + TRAINER_CLASS(BATTLE_GIRL, "BATTLE GIRL", 6), + TRAINER_CLASS(PARASOL_LADY, "PARASOL LADY", 10), + TRAINER_CLASS(RS_SWIMMER_F, "SWIMMER♀", 2), + TRAINER_CLASS(RS_PICNICKER, "PICNICKER", 4), + TRAINER_CLASS(RS_TWINS, "TWINS", 3), + TRAINER_CLASS(RS_SAILOR, "SAILOR", 8), TRAINER_CLASS(BOARDER, "BOARDER"), - TRAINER_CLASS(COLLECTOR, "COLLECTOR"), - TRAINER_CLASS(PKMN_TRAINER, "{PKMN} TRAINER"), - TRAINER_CLASS(RS_PKMN_BREEDER, "{PKMN} BREEDER"), - TRAINER_CLASS(RS_PKMN_RANGER, "{PKMN} RANGER"), - TRAINER_CLASS(MAGMA_LEADER, "MAGMA LEADER"), - TRAINER_CLASS(TEAM_MAGMA, "TEAM MAGMA"), - TRAINER_CLASS(RS_LASS, "LASS"), - TRAINER_CLASS(RS_BUG_CATCHER, "BUG CATCHER"), - TRAINER_CLASS(RS_HIKER, "HIKER"), - TRAINER_CLASS(RS_YOUNG_COUPLE, "YOUNG COUPLE"), - TRAINER_CLASS(OLD_COUPLE, "OLD COUPLE"), - TRAINER_CLASS(RS_SIS_AND_BRO, "SIS AND BRO"), - TRAINER_CLASS(AQUA_ADMIN, "AQUA ADMIN"), - TRAINER_CLASS(MAGMA_ADMIN, "MAGMA ADMIN"), - TRAINER_CLASS(YOUNGSTER, "YOUNGSTER"), - TRAINER_CLASS(BUG_CATCHER, "BUG CATCHER"), - TRAINER_CLASS(LASS, "LASS"), - TRAINER_CLASS(SAILOR, "SAILOR"), - TRAINER_CLASS(CAMPER, "CAMPER"), - TRAINER_CLASS(PICNICKER, "PICNICKER"), - TRAINER_CLASS(POKEMANIAC, "POKéMANIAC"), - TRAINER_CLASS(SUPER_NERD, "SUPER NERD"), - TRAINER_CLASS(HIKER, "HIKER"), - TRAINER_CLASS(BIKER, "BIKER"), - TRAINER_CLASS(BURGLAR, "BURGLAR"), - TRAINER_CLASS(ENGINEER, "ENGINEER"), - TRAINER_CLASS(FISHERMAN, "FISHERMAN"), - TRAINER_CLASS(SWIMMER_M, "SWIMMER♂"), - TRAINER_CLASS(CUE_BALL, "CUE BALL"), - TRAINER_CLASS(GAMER, "GAMER"), - TRAINER_CLASS(BEAUTY, "BEAUTY"), - TRAINER_CLASS(SWIMMER_F, "SWIMMER♀"), - TRAINER_CLASS(PSYCHIC, "PSYCHIC"), - TRAINER_CLASS(ROCKER, "ROCKER"), - TRAINER_CLASS(JUGGLER, "JUGGLER"), - TRAINER_CLASS(TAMER, "TAMER"), - TRAINER_CLASS(BIRD_KEEPER, "BIRD KEEPER"), - TRAINER_CLASS(BLACK_BELT, "BLACK BELT"), - TRAINER_CLASS(RIVAL_EARLY, "RIVAL"), - TRAINER_CLASS(SCIENTIST, "SCIENTIST"), - TRAINER_CLASS(BOSS, "BOSS"), - TRAINER_CLASS(LEADER, "LEADER"), - TRAINER_CLASS(TEAM_ROCKET, "TEAM ROCKET"), - TRAINER_CLASS(COOLTRAINER, "COOLTRAINER"), - TRAINER_CLASS(ELITE_FOUR, "ELITE FOUR"), - TRAINER_CLASS(GENTLEMAN, "GENTLEMAN"), - TRAINER_CLASS(RIVAL_LATE, "RIVAL"), - TRAINER_CLASS(CHAMPION, "CHAMPION"), - TRAINER_CLASS(CHANNELER, "CHANNELER"), - TRAINER_CLASS(TWINS, "TWINS"), - TRAINER_CLASS(COOL_COUPLE, "COOL COUPLE"), - TRAINER_CLASS(YOUNG_COUPLE, "YOUNG COUPLE"), - TRAINER_CLASS(CRUSH_KIN, "CRUSH KIN"), - TRAINER_CLASS(SIS_AND_BRO, "SIS AND BRO"), - TRAINER_CLASS(PKMN_PROF, "{PKMN} PROF."), - TRAINER_CLASS(PLAYER, "PLAYER"), - TRAINER_CLASS(CRUSH_GIRL, "CRUSH GIRL"), - TRAINER_CLASS(TUBER, "TUBER"), - TRAINER_CLASS(PKMN_BREEDER, "{PKMN} BREEDER"), - TRAINER_CLASS(PKMN_RANGER, "{PKMN} RANGER"), - TRAINER_CLASS(AROMA_LADY, "AROMA LADY"), - TRAINER_CLASS(RUIN_MANIAC, "RUIN MANIAC"), - TRAINER_CLASS(LADY, "LADY"), - TRAINER_CLASS(PAINTER, "PAINTER"), + TRAINER_CLASS(COLLECTOR, "COLLECTOR", 15), + TRAINER_CLASS(PKMN_TRAINER, "{PKMN} TRAINER", 15), + TRAINER_CLASS(RS_PKMN_BREEDER, "{PKMN} BREEDER", 10), + TRAINER_CLASS(RS_PKMN_RANGER, "{PKMN} RANGER", 12), + TRAINER_CLASS(MAGMA_LEADER, "MAGMA LEADER", 20), + TRAINER_CLASS(TEAM_MAGMA, "TEAM MAGMA", 5), + TRAINER_CLASS(RS_LASS, "LASS", 4), + TRAINER_CLASS(RS_BUG_CATCHER, "BUG CATCHER", 4), + TRAINER_CLASS(RS_HIKER, "HIKER", 10), + TRAINER_CLASS(RS_YOUNG_COUPLE, "YOUNG COUPLE", 8), + TRAINER_CLASS(OLD_COUPLE, "OLD COUPLE", 10), + TRAINER_CLASS(RS_SIS_AND_BRO, "SIS AND BRO", 3), + TRAINER_CLASS(AQUA_ADMIN, "AQUA ADMIN", 10), + TRAINER_CLASS(MAGMA_ADMIN, "MAGMA ADMIN", 10), + TRAINER_CLASS(YOUNGSTER, "YOUNGSTER", 4), + TRAINER_CLASS(BUG_CATCHER, "BUG CATCHER", 3), + TRAINER_CLASS(LASS, "LASS", 4), + TRAINER_CLASS(SAILOR, "SAILOR", 8), + TRAINER_CLASS(CAMPER, "CAMPER", 5), + TRAINER_CLASS(PICNICKER, "PICNICKER", 5), + TRAINER_CLASS(POKEMANIAC, "POKéMANIAC", 12), + TRAINER_CLASS(SUPER_NERD, "SUPER NERD", 6), + TRAINER_CLASS(HIKER, "HIKER", 9), + TRAINER_CLASS(BIKER, "BIKER", 5), + TRAINER_CLASS(BURGLAR, "BURGLAR", 22), + TRAINER_CLASS(ENGINEER, "ENGINEER", 12), + TRAINER_CLASS(FISHERMAN, "FISHERMAN", 9), + TRAINER_CLASS(SWIMMER_M, "SWIMMER♂", 1), + TRAINER_CLASS(CUE_BALL, "CUE BALL", 6), + TRAINER_CLASS(GAMER, "GAMER", 18), + TRAINER_CLASS(BEAUTY, "BEAUTY", 18), + TRAINER_CLASS(SWIMMER_F, "SWIMMER♀", 1), + TRAINER_CLASS(PSYCHIC, "PSYCHIC", 5), + TRAINER_CLASS(ROCKER, "ROCKER", 6), + TRAINER_CLASS(JUGGLER, "JUGGLER", 10), + TRAINER_CLASS(TAMER, "TAMER", 10), + TRAINER_CLASS(BIRD_KEEPER, "BIRD KEEPER", 6), + TRAINER_CLASS(BLACK_BELT, "BLACK BELT", 6), + TRAINER_CLASS(RIVAL_EARLY, "RIVAL", 4), + TRAINER_CLASS(SCIENTIST, "SCIENTIST", 12), + TRAINER_CLASS(BOSS, "BOSS", 25), + TRAINER_CLASS(LEADER, "LEADER", 25), + TRAINER_CLASS(TEAM_ROCKET, "TEAM ROCKET", 8), + TRAINER_CLASS(COOLTRAINER, "COOLTRAINER", 9), + TRAINER_CLASS(ELITE_FOUR, "ELITE FOUR", 25), + TRAINER_CLASS(GENTLEMAN, "GENTLEMAN", 18), + TRAINER_CLASS(RIVAL_LATE, "RIVAL", 9), + TRAINER_CLASS(CHAMPION, "CHAMPION", 25), + TRAINER_CLASS(CHANNELER, "CHANNELER", 8), + TRAINER_CLASS(TWINS, "TWINS", 3), + TRAINER_CLASS(COOL_COUPLE, "COOL COUPLE", 6), + TRAINER_CLASS(YOUNG_COUPLE, "YOUNG COUPLE", 7), + TRAINER_CLASS(CRUSH_KIN, "CRUSH KIN", 6), + TRAINER_CLASS(SIS_AND_BRO, "SIS AND BRO", 1), + TRAINER_CLASS(PKMN_PROF, "{PKMN} PROF.", 25), + TRAINER_CLASS(PLAYER, "PLAYER", 1), + TRAINER_CLASS(CRUSH_GIRL, "CRUSH GIRL", 6), + TRAINER_CLASS(TUBER, "TUBER", 1), + TRAINER_CLASS(PKMN_BREEDER, "{PKMN} BREEDER", 7), + TRAINER_CLASS(PKMN_RANGER, "{PKMN} RANGER", 9), + TRAINER_CLASS(AROMA_LADY, "AROMA LADY", 7), + TRAINER_CLASS(RUIN_MANIAC, "RUIN MANIAC", 12), + TRAINER_CLASS(LADY, "LADY", 50), + TRAINER_CLASS(PAINTER, "PAINTER", 4), }; static const s8 sPlayerThrowXTranslation[] = { -32, -16, -16, -32, -32, 0, 0, 0 }; -// This is a factor in how much money you get for beating a trainer. -const struct TrainerMoney gTrainerMoneyTable[] = -{ - {TRAINER_CLASS_LEADER, 25}, - {TRAINER_CLASS_ELITE_FOUR, 25}, - {TRAINER_CLASS_PKMN_PROF, 25}, - {TRAINER_CLASS_RIVAL_EARLY, 4}, - {TRAINER_CLASS_RIVAL_LATE, 9}, - {TRAINER_CLASS_CHAMPION, 25}, - {TRAINER_CLASS_YOUNGSTER, 4}, - {TRAINER_CLASS_BUG_CATCHER, 3}, - {TRAINER_CLASS_HIKER, 9}, - {TRAINER_CLASS_BIRD_KEEPER, 6}, - {TRAINER_CLASS_PICNICKER, 5}, - {TRAINER_CLASS_SUPER_NERD, 6}, - {TRAINER_CLASS_FISHERMAN, 9}, - {TRAINER_CLASS_TEAM_ROCKET, 8}, - {TRAINER_CLASS_LASS, 4}, - {TRAINER_CLASS_BEAUTY, 18}, - {TRAINER_CLASS_BLACK_BELT, 6}, - {TRAINER_CLASS_CUE_BALL, 6}, - {TRAINER_CLASS_CHANNELER, 8}, - {TRAINER_CLASS_ROCKER, 6}, - {TRAINER_CLASS_GENTLEMAN, 18}, - {TRAINER_CLASS_BURGLAR, 22}, - {TRAINER_CLASS_SWIMMER_M, 1}, - {TRAINER_CLASS_ENGINEER, 12}, - {TRAINER_CLASS_JUGGLER, 10}, - {TRAINER_CLASS_SAILOR, 8}, - {TRAINER_CLASS_COOLTRAINER, 9}, - {TRAINER_CLASS_POKEMANIAC, 12}, - {TRAINER_CLASS_TAMER, 10}, - {TRAINER_CLASS_CAMPER, 5}, - {TRAINER_CLASS_PSYCHIC, 5}, - {TRAINER_CLASS_BIKER, 5}, - {TRAINER_CLASS_GAMER, 18}, - {TRAINER_CLASS_SCIENTIST, 12}, - {TRAINER_CLASS_CRUSH_GIRL, 6}, - {TRAINER_CLASS_TUBER, 1}, - {TRAINER_CLASS_PKMN_BREEDER, 7}, - {TRAINER_CLASS_PKMN_RANGER, 9}, - {TRAINER_CLASS_AROMA_LADY, 7}, - {TRAINER_CLASS_RUIN_MANIAC, 12}, - {TRAINER_CLASS_LADY, 50}, - {TRAINER_CLASS_PAINTER, 4}, - {TRAINER_CLASS_TWINS, 3}, - {TRAINER_CLASS_YOUNG_COUPLE, 7}, - {TRAINER_CLASS_SIS_AND_BRO, 1}, - {TRAINER_CLASS_COOL_COUPLE, 6}, - {TRAINER_CLASS_CRUSH_KIN, 6}, - {TRAINER_CLASS_SWIMMER_F, 1}, - {TRAINER_CLASS_PLAYER, 1}, - {TRAINER_CLASS_RS_LEADER, 25}, - {TRAINER_CLASS_RS_ELITE_FOUR, 25}, - {TRAINER_CLASS_RS_LASS, 4}, - {TRAINER_CLASS_RS_YOUNGSTER, 4}, - {TRAINER_CLASS_PKMN_TRAINER, 15}, - {TRAINER_CLASS_RS_HIKER, 10}, - {TRAINER_CLASS_RS_BEAUTY, 20}, - {TRAINER_CLASS_RS_FISHERMAN, 10}, - {TRAINER_CLASS_RS_LADY, 50}, - {TRAINER_CLASS_TRIATHLETE, 10}, - {TRAINER_CLASS_TEAM_AQUA, 5}, - {TRAINER_CLASS_RS_TWINS, 3}, - {TRAINER_CLASS_RS_SWIMMER_F, 2}, - {TRAINER_CLASS_RS_BUG_CATCHER, 4}, - {TRAINER_CLASS_SCHOOL_KID, 5}, - {TRAINER_CLASS_RICH_BOY, 50}, - {TRAINER_CLASS_SR_AND_JR, 4}, - {TRAINER_CLASS_RS_BLACK_BELT, 8}, - {TRAINER_CLASS_RS_TUBER_F, 1}, - {TRAINER_CLASS_HEX_MANIAC, 6}, - {TRAINER_CLASS_RS_PKMN_BREEDER, 10}, - {TRAINER_CLASS_TEAM_MAGMA, 5}, - {TRAINER_CLASS_INTERVIEWER, 12}, - {TRAINER_CLASS_RS_TUBER_M, 1}, - {TRAINER_CLASS_RS_YOUNG_COUPLE, 8}, - {TRAINER_CLASS_GUITARIST, 8}, - {TRAINER_CLASS_RS_GENTLEMAN, 20}, - {TRAINER_CLASS_RS_CHAMPION, 50}, - {TRAINER_CLASS_MAGMA_LEADER, 20}, - {TRAINER_CLASS_BATTLE_GIRL, 6}, - {TRAINER_CLASS_RS_SWIMMER_M, 2}, - {TRAINER_CLASS_POKEFAN, 20}, - {TRAINER_CLASS_EXPERT, 10}, - {TRAINER_CLASS_DRAGON_TAMER, 12}, - {TRAINER_CLASS_RS_BIRD_KEEPER, 8}, - {TRAINER_CLASS_NINJA_BOY, 3}, - {TRAINER_CLASS_PARASOL_LADY, 10}, - {TRAINER_CLASS_BUG_MANIAC, 15}, - {TRAINER_CLASS_RS_SAILOR, 8}, - {TRAINER_CLASS_COLLECTOR, 15}, - {TRAINER_CLASS_RS_PKMN_RANGER, 12}, - {TRAINER_CLASS_MAGMA_ADMIN, 10}, - {TRAINER_CLASS_RS_AROMA_LADY, 10}, - {TRAINER_CLASS_RS_RUIN_MANIAC, 15}, - {TRAINER_CLASS_RS_COOLTRAINER, 12}, - {TRAINER_CLASS_RS_POKEMANIAC, 15}, - {TRAINER_CLASS_KINDLER, 8}, - {TRAINER_CLASS_RS_CAMPER, 4}, - {TRAINER_CLASS_RS_PICNICKER, 4}, - {TRAINER_CLASS_RS_PSYCHIC, 6}, - {TRAINER_CLASS_RS_SIS_AND_BRO, 3}, - {TRAINER_CLASS_OLD_COUPLE, 10}, - {TRAINER_CLASS_AQUA_ADMIN, 10}, - {TRAINER_CLASS_AQUA_LEADER, 20}, - {TRAINER_CLASS_BOSS, 25}, - { 0xFF, 5}, -}; - static void (*const sTurnActionsFuncsTable[])(void) = { [B_ACTION_USE_MOVE] = HandleAction_UseMove, @@ -925,20 +799,31 @@ static void CB2_InitBattleInternal(void) SetGpuReg(REG_OFFSET_WINOUT, 0); gBattle_WIN0H = DISPLAY_WIDTH; - gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1); - ScanlineEffect_Clear(); - for (i = 0; i < 80; ++i) + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE)) { - gScanlineEffectRegBuffers[0][i] = 0xF0; - gScanlineEffectRegBuffers[1][i] = 0xF0; + gBattle_WIN0V = DISPLAY_HEIGHT - 1; + gBattle_WIN1H = DISPLAY_WIDTH; + gBattle_WIN1V = 32; } - for (; i < 160; ++i) + else { - gScanlineEffectRegBuffers[0][i] = 0xFF10; - gScanlineEffectRegBuffers[1][i] = 0xFF10; + gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1); + ScanlineEffect_Clear(); + + for (i = 0; i < 80; ++i) + { + gScanlineEffectRegBuffers[0][i] = 0xF0; + gScanlineEffectRegBuffers[1][i] = 0xF0; + } + for (; i < 160; ++i) + { + gScanlineEffectRegBuffers[0][i] = 0xFF10; + gScanlineEffectRegBuffers[1][i] = 0xFF10; + } + ScanlineEffect_SetParams(sIntroScanlineParams16Bit); } - ScanlineEffect_SetParams(sIntroScanlineParams16Bit); ResetPaletteFade(); gBattle_BG0_X = 0; @@ -965,7 +850,7 @@ static void CB2_InitBattleInternal(void) ResetTasks(); DrawBattleEntryBackground(); FreeAllSpritePalettes(); - gReservedSpritePaletteCount = 4; + gReservedSpritePaletteCount = MAX_BATTLERS_COUNT; SetVBlankCallback(VBlankCB_Battle); SetUpBattleVars(); @@ -981,8 +866,14 @@ static void CB2_InitBattleInternal(void) gMain.inBattle = TRUE; for (i = 0; i < PARTY_SIZE; i++) + { AdjustFriendship(&gPlayerParty[i], FRIENDSHIP_EVENT_LEAGUE_BATTLE); + // Apply party-wide start-of-battle form changes for both sides. + TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_BEGIN_BATTLE); + TryFormChange(i, B_SIDE_OPPONENT, FORM_CHANGE_BEGIN_BATTLE); + } + gBattleCommunication[MULTIUSE_STATE] = 0; } @@ -1210,9 +1101,11 @@ static void CB2_HandleStartBattle(void) RunTasks(); AnimateSprites(); BuildOamBuffer(); + playerMultiplayerId = GetMultiplayerId(); gBattleScripting.multiplayerId = playerMultiplayerId; enemyMultiplayerId = playerMultiplayerId ^ BIT_SIDE; + switch (gBattleCommunication[MULTIUSE_STATE]) { case 0: @@ -2284,7 +2177,10 @@ void SpriteCB_EnemyMon(struct Sprite *sprite) { sprite->callback = SpriteCB_MoveWildMonToRight; StartSpriteAnimIfDifferent(sprite, 0); - BeginNormalPaletteFade(0x20000, 0, 10, 10, RGB(8, 8, 8)); + if (WILD_DOUBLE_BATTLE) + BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 10, RGB(8, 8, 8)); + else + BeginNormalPaletteFade(0x20000, 0, 10, 10, RGB(8, 8, 8)); } static void SpriteCB_MoveWildMonToRight(struct Sprite *sprite) @@ -2308,7 +2204,10 @@ static void SpriteCB_WildMonShowHealthbox(struct Sprite *sprite) SetHealthboxSpriteVisible(gHealthboxSpriteIds[sprite->sBattler]); sprite->callback = SpriteCallbackDummy_2; StartSpriteAnimIfDifferent(sprite, 0); - BeginNormalPaletteFade(0x20000, 0, 10, 0, RGB(8, 8, 8)); + if (WILD_DOUBLE_BATTLE) + BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 0, RGB(8, 8, 8)); + else + BeginNormalPaletteFade(0x20000, 0, 10, 0, RGB(8, 8, 8)); } } @@ -2316,40 +2215,10 @@ void SpriteCallbackDummy_2(struct Sprite *sprite) { } -#define sNumFlickers data[3] -#define sDelay data[4] - -// Unused -static void SpriteCB_InitFlicker(struct Sprite *sprite) -{ - sprite->sNumFlickers = 6; - sprite->sDelay = 1; - sprite->callback = SpriteCB_Flicker; -} - -static void SpriteCB_Flicker(struct Sprite *sprite) -{ - sprite->sDelay--; - if (sprite->sDelay == 0) - { - sprite->sDelay = 8; - sprite->invisible ^= 1; - sprite->sNumFlickers--; - if (sprite->sNumFlickers == 0) - { - sprite->invisible = FALSE; - sprite->callback = SpriteCallbackDummy_2; - sFlickerArray[0] = 0; - } - } -} - -#undef sNumFlickers -#undef sDelay - void SpriteCB_FaintOpponentMon(struct Sprite *sprite) { u8 battler = sprite->sBattler; + u32 personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_PERSONALITY); u16 species; u8 yOffset; @@ -2358,29 +2227,15 @@ void SpriteCB_FaintOpponentMon(struct Sprite *sprite) else species = sprite->sSpeciesId; - GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_PERSONALITY); // Unused return value. - + species = SanitizeSpeciesId(species); if (species == SPECIES_UNOWN) - { - u32 personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_PERSONALITY); - u16 unownForm = GET_UNOWN_LETTER(personalityValue); - u16 unownSpecies; + species = GetUnownSpeciesId(personality); + yOffset = gSpeciesInfo[species].frontPicYOffset; - if (unownForm == 0) - unownSpecies = SPECIES_UNOWN; // Use the A Unown form. - else - unownSpecies = NUM_SPECIES + unownForm; // Use one of the other Unown letters. - - yOffset = gSpeciesInfo[unownSpecies].frontPicYOffset; - } - else if (species > NUM_SPECIES) - { - yOffset = gSpeciesInfo[SPECIES_NONE].frontPicYOffset; - } + if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies != 0) + species = gBattleSpritesDataPtr->battlerData[battler].transformSpecies; else - { - yOffset = gSpeciesInfo[species].frontPicYOffset; - } + species = sprite->sSpeciesId; sprite->data[3] = 8 - yOffset / 8; sprite->data[4] = 1; @@ -4927,24 +4782,23 @@ static void ReturnFromBattleToOverworld(void) RandomlyGivePartyPokerus(gPlayerParty); PartySpreadPokerus(gPlayerParty); } - if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) || !gReceivedRemoteLinkPlayers) + + if (gBattleTypeFlags & BATTLE_TYPE_LINK && gReceivedRemoteLinkPlayers) + return; + + gSpecialVar_Result = gBattleOutcome; + gMain.inBattle = FALSE; + gMain.callback1 = gPreBattleCallback1; + + if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) { - gSpecialVar_Result = gBattleOutcome; - gMain.inBattle = FALSE; - gMain.callback1 = gPreBattleCallback1; - if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) - { - UpdateRoamerHPStatus(&gEnemyParty[0]); -#ifdef BUGFIX - if ((gBattleOutcome == B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT) -#else - if ((gBattleOutcome & B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT) // Bug: When Roar is used by roamer, gBattleOutcome is B_OUTCOME_PLAYER_TELEPORTED (5). -#endif // & with B_OUTCOME_WON (1) will return TRUE and deactivates the roamer. - SetRoamerInactive(); - } - m4aSongNumStop(SE_LOW_HEALTH); - SetMainCallback2(gMain.savedCallback); + UpdateRoamerHPStatus(&gEnemyParty[0]); + if ((gBattleOutcome == B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT) + SetRoamerInactive(); } + + m4aSongNumStop(SE_LOW_HEALTH); + SetMainCallback2(gMain.savedCallback); } void RunBattleScriptCommands_PopCallbacksStack(void) @@ -4968,185 +4822,6 @@ void RunBattleScriptCommands(void) gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); } -static void HandleAction_WatchesCarefully(void) -{ - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - gBattle_BG0_X = 0; - gBattle_BG0_Y = 0; - if (gBattleStruct->safariRockThrowCounter != 0) - { - --gBattleStruct->safariRockThrowCounter; - if (gBattleStruct->safariRockThrowCounter == 0) - { - *(&gBattleStruct->safariCatchFactor) = gSpeciesInfo[GetMonData(gEnemyParty, MON_DATA_SPECIES)].catchRate * 100 / 1275; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_WATCHING; - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_ANGRY; - } - } - else - { - if (gBattleStruct->safariBaitThrowCounter != 0) - { - --gBattleStruct->safariBaitThrowCounter; - if (gBattleStruct->safariBaitThrowCounter == 0) - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_WATCHING; - else - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_EATING; - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_WATCHING; - } - } - gBattlescriptCurrInstr = gBattlescriptsForSafariActions[0]; - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; -} - -static void HandleAction_SafariZoneBallThrow(void) -{ - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - gBattle_BG0_X = 0; - gBattle_BG0_Y = 0; - --gNumSafariBalls; - gLastUsedItem = ITEM_SAFARI_BALL; - gBattlescriptCurrInstr = BattleScript_SafariBallThrow; - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; -} - -static void HandleAction_ThrowBait(void) -{ - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - gBattle_BG0_X = 0; - gBattle_BG0_Y = 0; - gBattleStruct->safariBaitThrowCounter += Random() % 5 + 2; - if (gBattleStruct->safariBaitThrowCounter > 6) - gBattleStruct->safariBaitThrowCounter = 6; - gBattleStruct->safariRockThrowCounter = 0; - gBattleStruct->safariCatchFactor >>= 1; - if (gBattleStruct->safariCatchFactor <= 2) - gBattleStruct->safariCatchFactor = 3; - gBattlescriptCurrInstr = gBattlescriptsForSafariActions[2]; - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; -} - -static void HandleAction_ThrowRock(void) -{ - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - gBattle_BG0_X = 0; - gBattle_BG0_Y = 0; - gBattleStruct->safariRockThrowCounter += Random() % 5 + 2; - if (gBattleStruct->safariRockThrowCounter > 6) - gBattleStruct->safariRockThrowCounter = 6; - gBattleStruct->safariBaitThrowCounter = 0; - gBattleStruct->safariCatchFactor <<= 1; - if (gBattleStruct->safariCatchFactor > 20) - gBattleStruct->safariCatchFactor = 20; - gBattlescriptCurrInstr = gBattlescriptsForSafariActions[1]; - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; -} - -static void HandleAction_SafariZoneRun(void) -{ - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - PlaySE(SE_FLEE); - gCurrentTurnActionNumber = gBattlersCount; - gBattleOutcome = B_OUTCOME_RAN; -} - -static void HandleAction_OldManBallThrow(void) -{ - gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - gBattle_BG0_X = 0; - gBattle_BG0_Y = 0; - PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker]) - gBattlescriptCurrInstr = gBattlescriptsForSafariActions[3]; - gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; - gActionsByTurnOrder[1] = B_ACTION_FINISHED; -} - -static void HandleAction_TryFinish(void) -{ - if (!HandleFaintedMonActions()) - { - gBattleStruct->faintedActionsState = 0; - gCurrentActionFuncId = B_ACTION_FINISHED; - } -} - -static void HandleAction_NothingIsFainted(void) -{ - ++gCurrentTurnActionNumber; - gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; - gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED - | HITMARKER_NO_PPDEDUCT | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_IGNORE_ON_AIR - | HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_PASSIVE_DAMAGE - | HITMARKER_OBEYS | HITMARKER_WAKE_UP_CLEAR | HITMARKER_SYNCHRONISE_EFFECT - | HITMARKER_CHARGING | HITMARKER_NEVER_SET); -} - -static void HandleAction_ActionFinished(void) -{ - u32 i, j; - bool32 afterYouActive = gSpecialStatuses[gBattlerByTurnOrder[gCurrentTurnActionNumber + 1]].afterYou; - *(gBattleStruct->monToSwitchIntoId + gBattlerByTurnOrder[gCurrentTurnActionNumber]) = gSelectedMonPartyId = PARTY_SIZE; - gCurrentTurnActionNumber++; - gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; - SpecialStatusesClear(); - gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED - | HITMARKER_NO_PPDEDUCT | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_PASSIVE_DAMAGE - | HITMARKER_OBEYS | HITMARKER_WAKE_UP_CLEAR | HITMARKER_SYNCHRONISE_EFFECT - | HITMARKER_CHARGING | HITMARKER_NEVER_SET | HITMARKER_IGNORE_DISGUISE); - - gCurrentMove = 0; - gBattleMoveDamage = 0; - gMoveResultFlags = 0; - gBattleScripting.animTurn = 0; - gBattleScripting.animTargetsHit = 0; - gLastLandedMoves[gBattlerAttacker] = 0; - gLastHitByType[gBattlerAttacker] = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleScripting.moveendState = 0; - gBattleCommunication[3] = 0; - gBattleCommunication[4] = 0; - gBattleScripting.multihitMoveEffect = 0; - gBattleResources->battleScriptsStack->size = 0; - gBattleStruct->dynamax.usingMaxMove[gBattlerAttacker] = 0; - - if (B_RECALC_TURN_AFTER_ACTIONS >= GEN_8 && !afterYouActive && !gBattleStruct->pledgeMove) - { - // i starts at `gCurrentTurnActionNumber` because we don't want to recalculate turn order for mon that have already - // taken action. It's been previously increased, which we want in order to not recalculate the turn of the mon that just finished its action - for (i = gCurrentTurnActionNumber; i < gBattlersCount - 1; i++) - { - for (j = i + 1; j < gBattlersCount; j++) - { - u32 battler1 = gBattlerByTurnOrder[i]; - u32 battler2 = gBattlerByTurnOrder[j]; - - if (gProtectStructs[battler1].quash || gProtectStructs[battler2].quash - || gProtectStructs[battler1].shellTrap || gProtectStructs[battler2].shellTrap) - continue; - - // We recalculate order only for action of the same priority. If any action other than switch/move has been taken, they should - // have been executed before. The only recalculation needed is for moves/switch. Mega evolution is handled in src/battle_main.c/TryChangeOrder - if((gActionsByTurnOrder[i] == B_ACTION_USE_MOVE && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE)) - { - if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) - SwapTurnOrder(i, j); - } - else if ((gActionsByTurnOrder[i] == B_ACTION_SWITCH && gActionsByTurnOrder[j] == B_ACTION_SWITCH)) - { - if (GetWhichBattlerFaster(battler1, battler2, TRUE) == -1) // If the actions chosen are switching, we recalc order but ignoring the moves - SwapTurnOrder(i, j); - } - } - } - } -} - void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) { u32 moveType, ateType, attackerAbility; @@ -5255,10 +4930,8 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) ) { gBattleStruct->dynamicMoveType = ateType | F_DYNAMIC_TYPE_SET; - // TODO: Dynamax - // if (!IsDynamaxed(battlerAtk)) - // gBattleStruct->ateBoost[battlerAtk] = 1; - gBattleStruct->ateBoost[battlerAtk] = 1; + if (!IsDynamaxed(battlerAtk)) + gBattleStruct->ateBoost[battlerAtk] = 1; } else if (gMovesInfo[move].type != TYPE_NORMAL && gMovesInfo[move].effect != EFFECT_HIDDEN_POWER @@ -5266,10 +4939,8 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) && attackerAbility == ABILITY_NORMALIZE) { gBattleStruct->dynamicMoveType = TYPE_NORMAL | F_DYNAMIC_TYPE_SET; - // TODO: Dynamax - // if (!IsDynamaxed(battlerAtk)) - // gBattleStruct->ateBoost[battlerAtk] = 1; - gBattleStruct->ateBoost[battlerAtk] = 1; + if (!IsDynamaxed(battlerAtk)) + gBattleStruct->ateBoost[battlerAtk] = 1; } else if (gMovesInfo[move].soundMove && attackerAbility == ABILITY_LIQUID_VOICE) { @@ -5295,6 +4966,26 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) } } +// special to set a field's totem boost(s) +// inputs: +// var8000: battler +// var8001 - var8007: stat changes +void SetTotemBoost(void) +{ + u32 battler = gSpecialVar_0x8000; + u32 i; + + for (i = 0; i < (NUM_BATTLE_STATS - 1); i++) + { + if (*(&gSpecialVar_0x8001 + i)) + { + gQueuedStatBoosts[battler].stats |= (1 << i); + gQueuedStatBoosts[battler].statChanges[i] = *(&gSpecialVar_0x8001 + i); + gQueuedStatBoosts[battler].stats |= 0x80; // used as a flag for the "totem flared to life" script + } + } +} + bool32 IsWildMonSmart(void) { #if B_SMART_WILD_AI_FLAG != 0 @@ -5303,7 +4994,3 @@ bool32 IsWildMonSmart(void) return FALSE; #endif } - - - - diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index de0a85bba..c7fd32cee 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7528,14 +7528,11 @@ static u32 GetTrainerMoneyToGive(u16 trainerId) } else { - // TODO: Update Trainer struct - // const struct TrainerMon *party = GetTrainerPartyFromId(trainerId); - // if (party == NULL) - // return 20; - // lastMonLevel = party[GetTrainerPartySizeFromId(trainerId) - 1].lvl; - // trainerMoney = gTrainerClasses[GetTrainerClassFromId(trainerId)].money; - lastMonLevel = 10; - trainerMoney = 100; + const struct TrainerMon *party = GetTrainerPartyFromId(trainerId); + if (party == NULL) + return 20; + lastMonLevel = party[GetTrainerPartySizeFromId(trainerId) - 1].lvl; + trainerMoney = gTrainerClasses[GetTrainerClassFromId(trainerId)].money; if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * trainerMoney; diff --git a/src/battle_util.c b/src/battle_util.c index 84016a554..d41b84320 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -19,6 +19,8 @@ #include "battle_scripts.h" #include "battle_message.h" #include "malloc.h" +#include "safari_zone.h" +#include "sound.h" #include "constants/battle_anim.h" #include "battle_controllers.h" #include "constants/battle.h" @@ -30,6 +32,7 @@ #include "constants/hold_effects.h" #include "constants/battle_move_effects.h" #include "constants/battle_script_commands.h" +#include "constants/songs.h" static bool32 TryRemoveScreens(u32 battler); static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler); @@ -467,6 +470,194 @@ void HandleAction_Run(void) } } +void HandleAction_WatchesCarefully(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + if (gBattleStruct->safariRockThrowCounter != 0) + { + gBattleStruct->safariRockThrowCounter--; + if (gBattleStruct->safariRockThrowCounter == 0) + { + gBattleStruct->safariCatchFactor = gSpeciesInfo[GetMonData(gEnemyParty, MON_DATA_SPECIES)].catchRate * 100 / 1275; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_WATCHING; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_ANGRY; + } + } + else + { + if (gBattleStruct->safariBaitThrowCounter != 0) + { + --gBattleStruct->safariBaitThrowCounter; + if (gBattleStruct->safariBaitThrowCounter == 0) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_WATCHING; + else + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_EATING; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MON_WATCHING; + } + } + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[0]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +void HandleAction_SafariZoneBallThrow(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gNumSafariBalls--; + gLastUsedItem = ITEM_SAFARI_BALL; + gBattlescriptCurrInstr = BattleScript_SafariBallThrow; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +void HandleAction_ThrowBait(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + + gBattleStruct->safariBaitThrowCounter += Random() % 5 + 2; + if (gBattleStruct->safariBaitThrowCounter > 6) + gBattleStruct->safariBaitThrowCounter = 6; + + gBattleStruct->safariRockThrowCounter = 0; + gBattleStruct->safariCatchFactor >>= 1; + + if (gBattleStruct->safariCatchFactor <= 2) + gBattleStruct->safariCatchFactor = 3; + + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[2]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +void HandleAction_ThrowRock(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + + gBattleStruct->safariRockThrowCounter += Random() % 5 + 2; + if (gBattleStruct->safariRockThrowCounter > 6) + gBattleStruct->safariRockThrowCounter = 6; + + gBattleStruct->safariBaitThrowCounter = 0; + gBattleStruct->safariCatchFactor <<= 1; + + if (gBattleStruct->safariCatchFactor > 20) + gBattleStruct->safariCatchFactor = 20; + + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[1]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +void HandleAction_SafariZoneRun(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + PlaySE(SE_FLEE); + gCurrentTurnActionNumber = gBattlersCount; + gBattleOutcome = B_OUTCOME_RAN; +} + +void HandleAction_OldManBallThrow(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker]) + + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[3]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + gActionsByTurnOrder[1] = B_ACTION_FINISHED; +} + +void HandleAction_TryFinish(void) +{ + if (!HandleFaintedMonActions()) + { + gBattleStruct->faintedActionsState = 0; + gCurrentActionFuncId = B_ACTION_FINISHED; + } +} + +void HandleAction_NothingIsFainted(void) +{ + ++gCurrentTurnActionNumber; + gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; + gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED + | HITMARKER_NO_PPDEDUCT | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_PASSIVE_DAMAGE + | HITMARKER_OBEYS | HITMARKER_WAKE_UP_CLEAR | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_CHARGING | HITMARKER_NEVER_SET); +} + +void HandleAction_ActionFinished(void) +{ + u32 i, j; + bool32 afterYouActive = gSpecialStatuses[gBattlerByTurnOrder[gCurrentTurnActionNumber + 1]].afterYou; + *(gBattleStruct->monToSwitchIntoId + gBattlerByTurnOrder[gCurrentTurnActionNumber]) = gSelectedMonPartyId = PARTY_SIZE; + gCurrentTurnActionNumber++; + gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; + SpecialStatusesClear(); + gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED + | HITMARKER_NO_PPDEDUCT | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_PASSIVE_DAMAGE + | HITMARKER_OBEYS | HITMARKER_WAKE_UP_CLEAR | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_CHARGING | HITMARKER_NEVER_SET | HITMARKER_IGNORE_DISGUISE); + + gCurrentMove = 0; + gBattleMoveDamage = 0; + gMoveResultFlags = 0; + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + gLastLandedMoves[gBattlerAttacker] = 0; + gLastHitByType[gBattlerAttacker] = 0; + gBattleStruct->dynamicMoveType = 0; + gBattleScripting.moveendState = 0; + gBattleCommunication[3] = 0; + gBattleCommunication[4] = 0; + gBattleScripting.multihitMoveEffect = 0; + gBattleResources->battleScriptsStack->size = 0; + gBattleStruct->dynamax.usingMaxMove[gBattlerAttacker] = 0; + + if (B_RECALC_TURN_AFTER_ACTIONS >= GEN_8 && !afterYouActive && !gBattleStruct->pledgeMove) + { + // i starts at `gCurrentTurnActionNumber` because we don't want to recalculate turn order for mon that have already + // taken action. It's been previously increased, which we want in order to not recalculate the turn of the mon that just finished its action + for (i = gCurrentTurnActionNumber; i < gBattlersCount - 1; i++) + { + for (j = i + 1; j < gBattlersCount; j++) + { + u32 battler1 = gBattlerByTurnOrder[i]; + u32 battler2 = gBattlerByTurnOrder[j]; + + if (gProtectStructs[battler1].quash || gProtectStructs[battler2].quash + || gProtectStructs[battler1].shellTrap || gProtectStructs[battler2].shellTrap) + continue; + + // We recalculate order only for action of the same priority. If any action other than switch/move has been taken, they should + // have been executed before. The only recalculation needed is for moves/switch. Mega evolution is handled in src/battle_main.c/TryChangeOrder + if((gActionsByTurnOrder[i] == B_ACTION_USE_MOVE && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE)) + { + if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) + SwapTurnOrder(i, j); + } + else if ((gActionsByTurnOrder[i] == B_ACTION_SWITCH && gActionsByTurnOrder[j] == B_ACTION_SWITCH)) + { + if (GetWhichBattlerFaster(battler1, battler2, TRUE) == -1) // If the actions chosen are switching, we recalc order but ignoring the moves + SwapTurnOrder(i, j); + } + } + } + } +} + u8 GetBattlerForBattleScript(u8 caseId) { diff --git a/src/berry.c b/src/berry.c index a2e5900a8..5c29b1794 100644 --- a/src/berry.c +++ b/src/berry.c @@ -1004,12 +1004,14 @@ const struct Berry * GetBerryInfo(u8 berryIdx) return &gBerries[berryIdx - 1]; } -u8 ItemIdToBerryType(u16 itemId) +u8 ItemIdToBerryType(u16 item) { - if (itemId - FIRST_BERRY_INDEX < 0 || itemId - FIRST_BERRY_INDEX > ITEM_ENIGMA_BERRY - FIRST_BERRY_INDEX) - return 1; + u16 berry = item - FIRST_BERRY_INDEX; - return ITEM_TO_BERRY(itemId); + if (berry > LAST_BERRY_INDEX - FIRST_BERRY_INDEX) + return ITEM_TO_BERRY(FIRST_BERRY_INDEX); + else + return ITEM_TO_BERRY(item); } u16 BerryTypeToItemId(u16 berryType) From 7e2ecf588e4a8b19ae8707e17f8662dc97ce139f Mon Sep 17 00:00:00 2001 From: cawtds Date: Sun, 12 May 2024 22:39:03 +0200 Subject: [PATCH 11/11] fixed 1v2 double battles, added wild double battles, removed unused --- include/battle.h | 8 +-- include/battle_setup.h | 1 + include/pokemon.h | 1 - include/text.h | 2 +- include/wild_encounter.h | 1 + src/battle_anim_effects_3.c | 2 +- src/battle_anim_mons.c | 17 ++--- src/battle_anim_special.c | 16 ++--- src/battle_controller_player.c | 125 ++++++++++++++++++++++++--------- src/battle_controllers.c | 40 +++++------ src/battle_gfx_sfx_util.c | 25 +++---- src/battle_interface.c | 73 ++++++++++--------- src/battle_intro.c | 2 +- src/battle_main.c | 15 ++-- src/battle_message.c | 18 +++-- src/battle_setup.c | 13 +++- src/battle_util.c | 37 ++++++---- src/party_menu.c | 14 ++-- src/pokeball.c | 32 ++++++--- src/pokemon.c | 7 -- src/reshow_battle_screen.c | 11 +-- src/text.c | 2 +- src/wild_encounter.c | 37 +++++++++- 23 files changed, 308 insertions(+), 191 deletions(-) diff --git a/include/battle.h b/include/battle.h index 56061557a..c9eeb3b0b 100644 --- a/include/battle.h +++ b/include/battle.h @@ -873,6 +873,9 @@ struct BattleHealthboxInfo u8 triedShinyMonAnim : 1; // x80 u8 finishedShinyMonAnim : 1; // x1 u8 opponentDrawPartyStatusSummaryDelay : 5; // x2 + u8 bgmRestored:1; + u8 waitForCry:1; + u8 healthboxSlideInStarted:1; u8 healthboxBounceSpriteId; u8 battlerBounceSpriteId; u8 animationState; @@ -914,7 +917,7 @@ extern u8 *gLinkBattleRecvBuffer; struct MonSpritesGfx { void *firstDecompressed; // ptr to the decompressed sprite of the first pokemon - void *sprites[MAX_BATTLERS_COUNT]; + u8 *sprites[MAX_BATTLERS_COUNT]; struct SpriteTemplate templates[MAX_BATTLERS_COUNT]; struct SpriteFrameImage images[MAX_BATTLERS_COUNT][4]; u8 field_F4[0x80 - (4 * MAX_BATTLERS_COUNT)]; // unused, original - spritesGfx @@ -978,10 +981,7 @@ extern bool8 gTransformedShininess[MAX_BATTLERS_COUNT]; extern u8 gBattlerPositions[MAX_BATTLERS_COUNT]; extern u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT]; extern u8 gBattleOutcome; -extern u8 gBattleMonForms[MAX_BATTLERS_COUNT]; extern u32 gBattleControllerExecFlags; -// extern u8 gBattleBufferA[MAX_BATTLERS_COUNT][0x200]; -// extern u8 gBattleBufferB[MAX_BATTLERS_COUNT][0x200]; extern u8 gActionSelectionCursor[MAX_BATTLERS_COUNT]; extern void (*gPreBattleCallback1)(void); extern bool8 gDoingBattleAnim; diff --git a/include/battle_setup.h b/include/battle_setup.h index 9a93cd55a..6937d2e9a 100644 --- a/include/battle_setup.h +++ b/include/battle_setup.h @@ -6,6 +6,7 @@ extern u16 gPartnerTrainerId; void StartWildBattle(void); +void StartDoubleWildBattle(void); void StartRoamerBattle(void); void StartOldManTutorialBattle(void); void StartScriptedWildBattle(void); diff --git a/include/pokemon.h b/include/pokemon.h index 4fbdb690c..95266cf8e 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -779,7 +779,6 @@ u8 GetMoveRelearnerMoves(struct Pokemon *mon, u16 *moves); u8 GetLevelUpMovesBySpecies(u16 species, u16 *moves); u8 GetNumberOfRelearnableMoves(struct Pokemon *mon); u16 SpeciesToPokedexNum(u16 species); -void ClearBattleMonForms(void); void PlayBattleBGM(void); void PlayMapChosenOrBattleBGM(u16 songId); const u32 *GetMonFrontSpritePal(struct Pokemon *mon); diff --git a/include/text.h b/include/text.h index 7090a029b..76419b0b7 100644 --- a/include/text.h +++ b/include/text.h @@ -178,7 +178,7 @@ void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *c u16 RenderText(struct TextPrinter *textPrinter); s32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32); s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing); -u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str, int a3, int a4, int a5, int a6, int a7); +u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str); u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y); u8 GetKeypadIconTileOffset(u8 keypadIconId); u8 GetKeypadIconWidth(u8 keypadIconId); diff --git a/include/wild_encounter.h b/include/wild_encounter.h index 066366dc7..2e6804e21 100644 --- a/include/wild_encounter.h +++ b/include/wild_encounter.h @@ -51,5 +51,6 @@ bool8 SweetScentWildEncounter(void); void SeedWildEncounterRng(u16 randVal); void ResetEncounterRateModifiers(void); bool8 TryStandardWildEncounter(u32 currMetatileAttrs); +bool8 TryDoDoubleWildBattle(void); #endif // GUARD_WILD_ENCOUNTER_H diff --git a/src/battle_anim_effects_3.c b/src/battle_anim_effects_3.c index e5911cbf8..fc5376aa0 100644 --- a/src/battle_anim_effects_3.c +++ b/src/battle_anim_effects_3.c @@ -2300,7 +2300,7 @@ void AnimTask_TransformMon(u8 taskId) else position = GetBattlerPosition(gBattleAnimAttacker); - src = gMonSpritesGfxPtr->sprites[position] + (gBattleMonForms[gBattleAnimAttacker] << 11); + src = gMonSpritesGfxPtr->sprites[position]; dest = animBg.bgTiles; CpuCopy32(src, dest, MON_PIC_SIZE); LoadBgTiles(1, animBg.bgTiles, 0x800, animBg.tilesOffset); diff --git a/src/battle_anim_mons.c b/src/battle_anim_mons.c index 8dd3aca48..3244a3deb 100644 --- a/src/battle_anim_mons.c +++ b/src/battle_anim_mons.c @@ -1,6 +1,7 @@ #include "global.h" #include "gflib.h" #include "battle_anim.h" +#include "battle_interface.h" #include "data.h" #include "decompress.h" #include "pokemon_icon.h" @@ -86,10 +87,10 @@ u8 GetBattlerSpriteCoord(u8 battlerId, u8 coordType) { case BATTLER_COORD_X: case BATTLER_COORD_X_2: - retVal = sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].x; + retVal = sBattlerCoords[WhichBattleCoords(battlerId)][GetBattlerPosition(battlerId)].x; break; case BATTLER_COORD_Y: - retVal = sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].y; + retVal = sBattlerCoords[WhichBattleCoords(battlerId)][GetBattlerPosition(battlerId)].y; break; case BATTLER_COORD_Y_PIC_OFFSET: case BATTLER_COORD_Y_PIC_OFFSET_DEFAULT: @@ -208,7 +209,7 @@ static u8 GetBattlerSpriteFinal_Y(u8 battlerId, u16 species, bool8 a3) offset = GetBattlerYDelta(battlerId, species); offset -= GetBattlerElevation(battlerId, species); } - y = offset + sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].y; + y = offset + sBattlerCoords[WhichBattleCoords(battlerId)][GetBattlerPosition(battlerId)].y; if (a3) { if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) @@ -782,16 +783,6 @@ void InitSpritePosToAnimAttacker(struct Sprite *sprite, bool8 respectMonPicOffse sprite->y += gBattleAnimArgs[1]; } -// u8 GetBattlerSide(u8 battlerId) -// { -// return GET_BATTLER_SIDE2(battlerId); -// } - -// u8 GetBattlerPosition(u8 battlerId) -// { -// return GET_BATTLER_POSITION(battlerId); -// } - u8 GetBattlerAtPosition(u8 position) { u8 i; diff --git a/src/battle_anim_special.c b/src/battle_anim_special.c index 183f86196..a1afa7cd7 100644 --- a/src/battle_anim_special.c +++ b/src/battle_anim_special.c @@ -2040,21 +2040,17 @@ void AnimTask_SetTargetToEffectBattler(u8 taskId) void TryShinyAnimation(u8 battler, struct Pokemon *mon) { bool32 isShiny; - u32 otId, personality; - u32 shinyValue; u8 taskId1, taskId2; + struct Pokemon* illusionMon; - isShiny = FALSE; + isShiny = GetMonData(mon, MON_DATA_IS_SHINY); gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = TRUE; - otId = GetMonData(mon, MON_DATA_OT_ID); - personality = GetMonData(mon, MON_DATA_PERSONALITY); + illusionMon = GetIllusionMonPtr(battler); + if (illusionMon != NULL) + mon = illusionMon; - if (IsBattlerSpriteVisible(battler)) + if (IsBattlerSpriteVisible(battler) && IsValidForBattle(mon)) { - shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality); - if (shinyValue < SHINY_ODDS) - isShiny = TRUE; - if (isShiny) { if (GetSpriteTileStartByTag(ANIM_TAG_GOLD_STARS) == 0xFFFF) diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index ed812768d..367e35f9c 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -1002,37 +1002,38 @@ static void Intro_DelayAndEnd(u32 battler) static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) { - bool8 var = FALSE; + bool8 healthboxAnimDone = FALSE; - if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI))) - { - if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy) - var = TRUE; - } - else + // Check if healthbox has finished sliding in + if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) { if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy && gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy) - var = TRUE; + healthboxAnimDone = TRUE; } - if (IsCryPlayingOrClearCrySongs()) - var = FALSE; - if (var && gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim + else + { + if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy) + healthboxAnimDone = TRUE; + } + + // If healthbox and shiny anim are done + if (healthboxAnimDone && gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim && gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim) { + // Reset shiny anim (even if it didn't occur) gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - m4aMPlayContinue(&gMPlayInfo_BGM); - else - m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 256); + HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[battler]], battler); - if (IsDoubleBattle()) + + if (TwoPlayerIntroMons(battler)) HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], BATTLE_PARTNER(battler)); + gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3; gBattlerControllerFuncs[battler] = Intro_DelayAndEnd; } @@ -1040,28 +1041,86 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) static void Intro_TryShinyAnimShowHealthbox(u32 battler) { - if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive) + bool32 bgmRestored = FALSE; + bool32 battlerAnimsDone = FALSE; + + // Start shiny animation if applicable for 1st Pokémon + if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim + && !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive) + TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]); + + // Start shiny animation if applicable for 2nd Pokémon + if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim + && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive) + TryShinyAnimation(BATTLE_PARTNER(battler), &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]); + + // Show healthbox after ball anim + if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive + && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive) { - if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim) - TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]); - if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim) - TryShinyAnimation(BATTLE_PARTNER(battler), &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]); - if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + if (!gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted) { - DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]); - UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], - &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], - HEALTHBOX_ALL); - StartHealthboxSlideIn(BATTLE_PARTNER(battler)); - SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]); + if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], HEALTHBOX_ALL); + StartHealthboxSlideIn(BATTLE_PARTNER(battler)); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]); + } + UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gPlayerParty[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL); + StartHealthboxSlideIn(battler); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]); } + gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = TRUE; + } + + // Restore bgm after cry has played and healthbox anim is started + if (!gBattleSpritesDataPtr->healthBoxesData[battler].waitForCry + && gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted + && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].waitForCry + && !IsCryPlayingOrClearCrySongs()) + { + if (!gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored) + { + if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK) + m4aMPlayContinue(&gMPlayInfo_BGM); + else + m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100); + } + gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = TRUE; + bgmRestored = TRUE; + } + + // Wait for battler anims + if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy + && gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy + && gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy + && gSprites[gBattlerSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy) + { + battlerAnimsDone = TRUE; + } + } + else + { + if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy + && gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy) + { + battlerAnimsDone = TRUE; + } + } + + // Clean up + if (bgmRestored && battlerAnimsDone) + { + if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]); DestroySprite(&gSprites[gBattleControllerData[battler]]); - UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], - &gPlayerParty[gBattlerPartyIndexes[battler]], - HEALTHBOX_ALL); - StartHealthboxSlideIn(battler); - SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]); + gBattleSpritesDataPtr->animationData->introAnimActive = FALSE; + gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = FALSE; + gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = FALSE; + gBattlerControllerFuncs[battler] = Intro_WaitForShinyAnimAndHealthbox; } } diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 87d76dfae..195623461 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -70,7 +70,6 @@ void SetUpBattleVars(void) HandleLinkBattleSetup(); gBattleControllerExecFlags = 0; ClearBattleAnimationVars(); - ClearBattleMonForms(); BattleAI_SetupItems(); BattleAI_SetupFlags(); } @@ -315,16 +314,13 @@ static void SetBattlePartyIds(void) { for (i = 0; i < gBattlersCount; i++) { - for (j = 0; j < PARTY_SIZE; ++j) + for (j = 0; j < PARTY_SIZE; j++) { if (i < 2) { - if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER) + if (GetBattlerSide(i) == B_SIDE_PLAYER) { - if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0 - && GetMonData(&gPlayerParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE - && GetMonData(&gPlayerParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG - && !GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG)) + if (IsValidForBattle(&gPlayerParty[j])) { gBattlerPartyIndexes[i] = j; break; @@ -332,10 +328,7 @@ static void SetBattlePartyIds(void) } else { - if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0 - && GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE - && GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG - && !GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG)) + if (IsValidForBattle(&gEnemyParty[j])) { gBattlerPartyIndexes[i] = j; break; @@ -344,13 +337,9 @@ static void SetBattlePartyIds(void) } else { - if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER) + if (GetBattlerSide(i) == B_SIDE_PLAYER) { - if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0 - && GetMonData(&gPlayerParty[j], MON_DATA_SPECIES) != SPECIES_NONE // Probably a typo by Game Freak. The rest use SPECIES2. - && GetMonData(&gPlayerParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG - && !GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG) - && gBattlerPartyIndexes[i - 2] != j) + if (IsValidForBattle(&gPlayerParty[j]) && gBattlerPartyIndexes[i - 2] != j) { gBattlerPartyIndexes[i] = j; break; @@ -358,19 +347,24 @@ static void SetBattlePartyIds(void) } else { - if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0 - && GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE - && GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG - && !GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG) - && gBattlerPartyIndexes[i - 2] != j) + if (IsValidForBattle(&gEnemyParty[j]) && gBattlerPartyIndexes[i - 2] != j) { gBattlerPartyIndexes[i] = j; break; } } + + // No valid mons were found. Add the empty slot. + if (gBattlerPartyIndexes[i - 2] == 0) + gBattlerPartyIndexes[i] = 1; + else + gBattlerPartyIndexes[i] = 0; } } } + + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + gBattlerPartyIndexes[1] = 0, gBattlerPartyIndexes[3] = 3; } } @@ -839,7 +833,7 @@ void BtlController_EmitChooseAction(u32 battler, u32 bufferId, u8 action, u16 it } // Unused -static void BtlController_EmitUnknownYesNoBox(u32 battler, u32 bufferId, u32 arg1) // TODO: Does the function name make sense for pokefirered? +static void BtlController_EmitUnknownYesNoBox(u32 battler, u32 bufferId, u32 arg1) { gBattleResources->transferBuffer[0] = CONTROLLER_UNKNOWNYESNOBOX; gBattleResources->transferBuffer[1] = arg1; diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 1a18a74f5..a86348899 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -139,11 +139,7 @@ void SpriteCB_WaitForBattlerBallReleaseAnim(struct Sprite *sprite) if (gSprites[spriteId].animPaused) gSprites[spriteId].animPaused = 0; else if (gSprites[spriteId].animEnded) - { - gSprites[spriteId].callback = SetIdleSpriteCallback; - StartSpriteAffineAnim(&gSprites[spriteId], 0); sprite->callback = SpriteCallbackDummy; - } } // Unused @@ -211,7 +207,6 @@ bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattler, u8 atkBattler, u8 de if (tableId == B_ANIM_FORM_CHANGE && (argument & 0x80)) { - gBattleMonForms[activeBattler] = (argument & ~(0x80)); return TRUE; } else if (gBattleSpritesDataPtr->battlerData[activeBattler].behindSubstitute @@ -313,6 +308,8 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler) u32 monsPersonality, currentPersonality, isShiny, species, paletteOffset, position; const void *lzPaletteData; struct Pokemon *illusionMon = GetIllusionMonPtr(battler); + if (illusionMon != NULL) + mon = illusionMon; if (GetMonData(mon, MON_DATA_IS_EGG) || GetMonData(mon, MON_DATA_SPECIES) == SPECIES_NONE) // Don't load GFX of egg pokemon. return; @@ -497,7 +494,12 @@ bool8 BattleLoadAllHealthBoxesGfx(u8 state) else { if (state == 2) - LoadCompressedSpriteSheetUsingHeap(&sSpriteSheets_DoublesPlayerHealthbox[0]); + { + if (WhichBattleCoords(0)) + LoadCompressedSpriteSheetUsingHeap(&sSpriteSheets_DoublesPlayerHealthbox[0]); + else + LoadCompressedSpriteSheetUsingHeap(&sSpriteSheet_SinglesPlayerHealthbox); + } else if (state == 3) LoadCompressedSpriteSheetUsingHeap(&sSpriteSheets_DoublesPlayerHealthbox[1]); else if (state == 4) @@ -697,7 +699,7 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo CpuCopy32(&gPlttBufferFaded[paletteOffset], &gPlttBufferUnfaded[paletteOffset], PLTT_SIZEOF(16)); gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies = targetSpecies; } - gBattleMonForms[battlerAtk] = gBattleMonForms[battlerDef]; + gSprites[gBattlerSpriteIds[battlerAtk]].y = GetBattlerSpriteDefault_Y(battlerAtk); StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerAtk]], 0); } @@ -717,11 +719,7 @@ void BattleLoadSubstituteOrMonSpriteGfx(u8 battlerId, bool8 loadMonSprite) LZDecompressVram(gSubstituteDollTilemap, gMonSpritesGfxPtr->sprites[position]); for (i = 1; i < 4; ++i) { - u8 (*ptr)[4][0x800] = gMonSpritesGfxPtr->sprites[position]; - - ++ptr; - --ptr; - DmaCopy32Defvars(3, (*ptr)[0], (*ptr)[i], 0x800); + Dma3CopyLarge32_(gMonSpritesGfxPtr->sprites[position], &gMonSpritesGfxPtr->sprites[position][MON_PIC_SIZE * i], MON_PIC_SIZE); } palOffset = OBJ_PLTT_ID(battlerId); LoadCompressedPalette(gSubstituteDollPal, palOffset, PLTT_SIZE_4BPP); @@ -738,7 +736,7 @@ void BattleLoadSubstituteOrMonSpriteGfx(u8 battlerId, bool8 loadMonSprite) void LoadBattleMonGfxAndAnimate(u8 battlerId, bool8 loadMonSprite, u8 spriteId) { BattleLoadSubstituteOrMonSpriteGfx(battlerId, loadMonSprite); - StartSpriteAnim(&gSprites[spriteId], gBattleMonForms[battlerId]); + StartSpriteAnim(&gSprites[spriteId], 0); if (!loadMonSprite) gSprites[spriteId].y = GetSubstituteSpriteDefault_Y(battlerId); else @@ -946,7 +944,6 @@ void BattleInterfaceSetWindowPals(void) void ClearTemporarySpeciesSpriteData(u8 battlerId, bool8 dontClearSubstitute) { gBattleSpritesDataPtr->battlerData[battlerId].transformSpecies = SPECIES_NONE; - gBattleMonForms[battlerId] = 0; if (!dontClearSubstitute) ClearBehindSubstituteBit(battlerId); } diff --git a/src/battle_interface.c b/src/battle_interface.c index d17b31e2e..5124036ab 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -67,7 +67,7 @@ struct TestingBar static void SpriteCB_HealthBoxOther(struct Sprite *sprite); static void SpriteCB_HealthBar(struct Sprite *sprite); static const u8 *GetBattleInterfaceGfxPtr(u8 which); -static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent); +static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, u32 maxOrCurrent, s16 currHp, s16 maxHp); static void Task_HidePartyStatusSummary_BattleStart_1(u8 taskId); static void Task_HidePartyStatusSummary_BattleStart_2(u8 taskId); static void SpriteCB_PartySummaryBar_Exit(struct Sprite *sprite); @@ -682,7 +682,7 @@ u8 CreateBattlerHealthboxSprites(u8 battlerId) u8 healthbarSpriteId; struct Sprite *healthbarSprite; - if (!IsDoubleBattle()) + if (WhichBattleCoords(battlerId) == 0) { if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) { @@ -864,7 +864,7 @@ void InitBattlerHealthboxCoords(u8 battler) { s16 x = 0, y = 0; - if (!IsDoubleBattle()) + if (!WhichBattleCoords(battler)) { if (GetBattlerSide(battler) != B_SIDE_PLAYER) x = 44, y = 30; @@ -910,7 +910,7 @@ static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl) if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER) { objVram = (void *)(OBJ_VRAM0); - if (!IsDoubleBattle()) + if (!WhichBattleCoords(gSprites[healthboxSpriteId].sBattlerId)) objVram += spriteTileNum + 0x820; else objVram += spriteTileNum + 0x420; @@ -929,7 +929,7 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp u32 windowId, spriteTileNum; u8 *windowTileData; - if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER && !IsDoubleBattle()) + if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER && !WhichBattleCoords(gSprites[healthboxSpriteId].sBattlerId)) { // Only in the Japanese release can HP be displayed as text outside of double battles u8 text[8]; @@ -960,12 +960,12 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp u8 text[20] = __("{COLOR 01}{HIGHLIGHT 02}"); battler = gSprites[healthboxSpriteId].sBattlerId; - if (IsDoubleBattle() == TRUE || GetBattlerSide(battler) == B_SIDE_OPPONENT) + if (WhichBattleCoords(battler) == TRUE || GetBattlerSide(battler) == B_SIDE_OPPONENT) { if (maxOrCurrent != HP_CURRENT) - UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, maxHp, maxOrCurrent); + UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, maxOrCurrent, currHp, maxHp); else - UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, currHp, maxOrCurrent); + UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, maxOrCurrent, currHp, maxHp); } else { @@ -992,7 +992,7 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp ConvertIntToDecimalStringN(text + 6, maxHp, STR_CONV_MODE_RIGHT_ALIGN, 3); else ConvertIntToDecimalStringN(text + 6, currHp, STR_CONV_MODE_RIGHT_ALIGN, 3); - RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0); + RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text); for (i = 0; i < 3; i++) { @@ -1006,7 +1006,7 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp static const u8 sText_Slash[] = _("/"); -static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent) +static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, u32 maxOrCurrent, s16 currHp, s16 maxHp) { u32 windowId, spriteTileNum; u8 *windowTileData; @@ -1027,11 +1027,15 @@ static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 var = 0; healthBarSpriteId = gSprites[healthboxSpriteId].sHealthBarSpriteId; - txtPtr = ConvertIntToDecimalStringN(text + 6, value, STR_CONV_MODE_RIGHT_ALIGN, 3); + if (maxOrCurrent == HP_CURRENT) + txtPtr = ConvertIntToDecimalStringN(text + 6, currHp, STR_CONV_MODE_RIGHT_ALIGN, 3); + else + txtPtr = ConvertIntToDecimalStringN(text + 6, maxHp, STR_CONV_MODE_RIGHT_ALIGN, 3); + if (maxOrCurrent == HP_CURRENT) StringCopy(txtPtr, sText_Slash); - RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0); + RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text); for (i = var; i < var + 3; i++) { @@ -1082,7 +1086,7 @@ static void PrintSafariMonInfo(u8 healthboxSpriteId, struct Pokemon *mon) var = 5; nature = GetNature(mon); StringCopy(text + 6, gNatureNamePointers[nature]); - RenderTextHandleBold(barFontGfx, 0, text, 0, 0, 0, 0, 0); + RenderTextHandleBold(barFontGfx, 0, text); for (j = 6, i = 0; i < var; i++, j++) { @@ -1114,7 +1118,7 @@ static void PrintSafariMonInfo(u8 healthboxSpriteId, struct Pokemon *mon) ConvertIntToDecimalStringN(text + 9, gBattleStruct->safariEscapeFactor, STR_CONV_MODE_RIGHT_ALIGN, 2); text[5] = CHAR_SPACE; text[8] = CHAR_SLASH; - RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0); + RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text); j = healthBarSpriteId; // Needed to match for some reason. for (j = 0; j < 5; j++) @@ -1143,7 +1147,7 @@ void SwapHpBarsWithHpText(void) { if (gSprites[gHealthboxSpriteIds[i]].callback == SpriteCallbackDummy && GetBattlerSide(i) != B_SIDE_OPPONENT - && (IsDoubleBattle() || GetBattlerSide(i) != B_SIDE_PLAYER)) + && (WhichBattleCoords(i) || GetBattlerSide(i) != B_SIDE_PLAYER)) { bool8 noBars; @@ -1151,18 +1155,20 @@ void SwapHpBarsWithHpText(void) noBars = gBattleSpritesDataPtr->battlerData[i].hpNumbersNoBars; if (GetBattlerSide(i) == B_SIDE_PLAYER) { - if (!IsDoubleBattle()) + if (!WhichBattleCoords(i)) continue; if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) continue; if (noBars == TRUE) // bars to text { + s16 currHp = GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_HP); + s16 maxHp = GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP); healthBarSpriteId = gSprites[gHealthboxSpriteIds[i]].sHealthBarSpriteId; CpuFill32(0, (void *)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * TILE_SIZE_4BPP), 8 * TILE_SIZE_4BPP); - UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_HP), HP_CURRENT); - UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP), HP_MAX); + UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_CURRENT, currHp, maxHp); + UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_MAX, currHp, maxHp); } else // text to bars { @@ -1184,11 +1190,13 @@ void SwapHpBarsWithHpText(void) } else { + s16 currHp = GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_HP); + s16 maxHp = GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP); healthBarSpriteId = gSprites[gHealthboxSpriteIds[i]].sHealthBarSpriteId; CpuFill32(0, (void *)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * 32), 8 * TILE_SIZE_4BPP); - UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_HP), HP_CURRENT); - UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP), HP_MAX); + UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_CURRENT, currHp, maxHp); + UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_MAX, currHp, maxHp); } } else // text to bars @@ -1496,7 +1504,7 @@ u8 CreatePartyStatusSummarySprites(u8 battlerId, struct HpAndStatus *partyInfo, { isOpponent = TRUE; - if (!isSwitchingMons || !IsDoubleBattle()) + if (!isSwitchingMons || !WhichBattleCoords(battlerId)) x = 104, y = 40; else x = 104, y = 16; @@ -1935,7 +1943,7 @@ void UpdateNickInHealthbox(u8 healthboxSpriteId, struct Pokemon *mon) { TextIntoHealthboxObject((void *)(OBJ_VRAM0 + 0x40 + spriteTileNum), windowTileData, 6); ptr = (void *)(OBJ_VRAM0); - if (!IsDoubleBattle()) + if (!WhichBattleCoords(gSprites[healthboxSpriteId].sBattlerId)) ptr += spriteTileNum + 0x800; else ptr += spriteTileNum + 0x400; @@ -2005,7 +2013,7 @@ static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId) if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) { status = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_STATUS); - if (!IsDoubleBattle()) + if (!WhichBattleCoords(battlerId)) tileNumAdder = 0x1A; else tileNumAdder = 0x12; @@ -2065,7 +2073,7 @@ static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId) FillPalette(sStatusIconColors[statusPalId], pltAdder + OBJ_PLTT_OFFSET, PLTT_SIZEOF(1)); CpuCopy16(&gPlttBufferUnfaded[OBJ_PLTT_OFFSET + pltAdder], (u16 *)OBJ_PLTT + pltAdder, PLTT_SIZEOF(1)); CpuCopy32(statusGfxPtr, (void *)(OBJ_VRAM0 + (gSprites[healthboxSpriteId].oam.tileNum + tileNumAdder) * TILE_SIZE_4BPP), 3 * TILE_SIZE_4BPP); - if (IsDoubleBattle() == TRUE || GetBattlerSide(battlerId) == B_SIDE_OPPONENT) + if (WhichBattleCoords(battlerId) == TRUE || GetBattlerSide(battlerId) == B_SIDE_OPPONENT) { if (!gBattleSpritesDataPtr->battlerData[battlerId].hpNumbersNoBars) { @@ -2171,31 +2179,30 @@ static void UpdateLeftNoOfBallsTextOnHealthbox(u8 healthboxSpriteId) void UpdateHealthboxAttribute(u8 healthboxSpriteId, struct Pokemon *mon, u8 elementId) { - s32 maxHp, currHp; u8 battlerId = gSprites[healthboxSpriteId].sBattlerId; + s32 maxHp = GetMonData(mon, MON_DATA_MAX_HP); + s32 currHp = GetMonData(mon, MON_DATA_HP); - if (elementId == HEALTHBOX_ALL && !IsDoubleBattle()) - GetBattlerSide(battlerId); // Pointless function call. - - if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER) + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) { - u8 isDoubles; + u8 isDoubles = WhichBattleCoords(battlerId); - maxHp = GetMonData(mon, MON_DATA_MAX_HP); - currHp = GetMonData(mon, MON_DATA_HP); if (elementId == HEALTHBOX_LEVEL || elementId == HEALTHBOX_ALL) UpdateLvlInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_LEVEL)); + + if (elementId == HEALTHBOX_CURRENT_HP || elementId == HEALTHBOX_ALL) UpdateHpTextInHealthbox(healthboxSpriteId, HP_CURRENT, currHp, maxHp); if (elementId == HEALTHBOX_MAX_HP || elementId == HEALTHBOX_ALL) UpdateHpTextInHealthbox(healthboxSpriteId, HP_MAX, currHp, maxHp); + if (elementId == HEALTHBOX_HEALTH_BAR || elementId == HEALTHBOX_ALL) { LoadBattleBarGfx(0); SetBattleBarStruct(battlerId, healthboxSpriteId, maxHp, currHp, 0); MoveBattleBar(battlerId, healthboxSpriteId, HEALTH_BAR, 0); } - isDoubles = IsDoubleBattle(); + if (!isDoubles && (elementId == HEALTHBOX_EXP_BAR || elementId == HEALTHBOX_ALL)) { u16 species; diff --git a/src/battle_intro.c b/src/battle_intro.c index 0b5b81ef0..bfc2c6fe3 100644 --- a/src/battle_intro.c +++ b/src/battle_intro.c @@ -471,7 +471,7 @@ void CopyBattlerSpriteToBg(s32 bgId, u8 x, u8 y, u8 battlerPosition, u8 palno, u u8 battler = GetBattlerAtPosition(battlerPosition); s32 offset = tilesOffset; - CpuCopy16(gMonSpritesGfxPtr->sprites[battlerPosition] + BG_SCREEN_SIZE * gBattleMonForms[battler], tilesDest, BG_SCREEN_SIZE); + CpuCopy16(gMonSpritesGfxPtr->sprites[battlerPosition], tilesDest, BG_SCREEN_SIZE); LoadBgTiles(bgId, tilesDest, 0x1000, tilesOffset); for (i = y; i < y + 8; ++i) for (j = x; j < x + 8; ++j) diff --git a/src/battle_main.c b/src/battle_main.c index d433eef9b..056f041d3 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -193,7 +193,6 @@ EWRAM_DATA struct BattleSpriteData *gBattleSpritesDataPtr = NULL; EWRAM_DATA struct MonSpritesGfx *gMonSpritesGfxPtr = NULL; EWRAM_DATA u16 gBattleMovePower = 0; EWRAM_DATA u16 gMoveToLearn = 0; -EWRAM_DATA u8 gBattleMonForms[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA u8 gPartyCriticalHits[PARTY_SIZE] = {0}; EWRAM_DATA u32 gFieldStatuses = 0; EWRAM_DATA u8 gBattlerAbility = 0; @@ -861,7 +860,10 @@ static void CB2_InitBattleInternal(void) if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) { CreateNPCTrainerParty(&gEnemyParty[0], gTrainerBattleOpponent_A, FALSE); + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && !BATTLE_TWO_VS_ONE_OPPONENT) + CreateNPCTrainerParty(&gEnemyParty[PARTY_SIZE / 2], gTrainerBattleOpponent_B, FALSE); SetWildMonHeldItem(); + CalculateEnemyPartyCount(); } gMain.inBattle = TRUE; @@ -1627,12 +1629,14 @@ static void CB2_HandleStartMultiBattle(void) break; case 5: case 9: + case 13: ++gBattleCommunication[0]; - gBattleCommunication[SPRITES_INIT_STATE1] = 1; + gBattleCommunication[1] = 1; // fall through case 6: case 10: - if (--gBattleCommunication[SPRITES_INIT_STATE1] == 0) + case 14: + if (--gBattleCommunication[1] == 0) ++gBattleCommunication[0]; break; } @@ -2257,11 +2261,11 @@ static void SpriteCB_AnimFaintOpponent(struct Sprite *sprite) } else // Erase bottom part of the sprite to create a smooth illusion of mon falling down. { - u8 *dst = (u8 *)gMonSpritesGfxPtr->sprites[GetBattlerPosition(sprite->sBattler)] + (gBattleMonForms[sprite->sBattler] << 11) + (sprite->data[3] << 8); + u8 *dst = &gMonSpritesGfxPtr->sprites[GetBattlerPosition(sprite->sBattler)][(sprite->data[3] << 8)]; for (i = 0; i < 0x100; i++) *(dst++) = 0; - StartSpriteAnim(sprite, gBattleMonForms[sprite->sBattler]); + StartSpriteAnim(sprite, 0); } } } @@ -3190,6 +3194,7 @@ static void DoBattleIntro(void) } break; } + } static void TryDoEventsBeforeFirstTurn(void) diff --git a/src/battle_message.c b/src/battle_message.c index f06f37b2f..10731c0fc 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -2478,7 +2478,7 @@ void BufferStringBattle(u32 battler, u16 stringId) } else if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY) stringPtr = sText_WildPkmnAppeared2; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) // interesting, looks like they had something planned for wild double battles + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]])) // interesting, looks like they had something planned for wild double battles stringPtr = sText_TwoWildPkmnAppeared; else if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL) stringPtr = sText_WildPkmnAppearedPause; @@ -2489,9 +2489,13 @@ void BufferStringBattle(u32 battler, u16 stringId) case STRINGID_INTROSENDOUT: // poke first send-out if (GetBattlerSide(battler) == B_SIDE_PLAYER) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]])) { - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + stringPtr = sText_InGamePartnerSentOutZGoN; + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + stringPtr = sText_GoTwoPkmn; + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) stringPtr = sText_LinkPartnerSentOutPkmnGoPkmn; else stringPtr = sText_GoTwoPkmn; @@ -2503,9 +2507,13 @@ void BufferStringBattle(u32 battler, u16 stringId) } else { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]])) { - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + if (BATTLE_TWO_VS_ONE_OPPONENT) + stringPtr = sText_Trainer1SentOutTwoPkmn; + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + stringPtr = sText_TwoTrainersSentPkmn; + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) stringPtr = sText_TwoLinkTrainersSentOutPkmn; else if (gBattleTypeFlags & BATTLE_TYPE_LINK) stringPtr = sText_LinkTrainerSentOutTwoPkmn; diff --git a/src/battle_setup.c b/src/battle_setup.c index 9093f5346..ab67a2699 100644 --- a/src/battle_setup.c +++ b/src/battle_setup.c @@ -59,7 +59,7 @@ struct TrainerBattleParameter static void DoSafariBattle(void); static void DoGhostBattle(void); -static void DoStandardWildBattle(void); +static void DoStandardWildBattle(bool32 isDouble); static void CB2_EndWildBattle(void); static u8 GetWildBattleTransition(void); static u8 GetTrainerBattleTransition(void); @@ -242,16 +242,23 @@ void StartWildBattle(void) else if (CheckSilphScopeInPokemonTower(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum)) DoGhostBattle(); else - DoStandardWildBattle(); + DoStandardWildBattle(FALSE); } -static void DoStandardWildBattle(void) +void StartDoubleWildBattle(void) +{ + DoStandardWildBattle(TRUE); +} + +static void DoStandardWildBattle(bool32 isDouble) { LockPlayerFieldControls(); FreezeObjectEvents(); StopPlayerAvatar(); gMain.savedCallback = CB2_EndWildBattle; gBattleTypeFlags = 0; + if (isDouble) + gBattleTypeFlags |= BATTLE_TYPE_DOUBLE; CreateBattleStartTask(GetWildBattleTransition(), 0); IncrementGameStat(GAME_STAT_TOTAL_BATTLES); IncrementGameStat(GAME_STAT_WILD_BATTLES); diff --git a/src/battle_util.c b/src/battle_util.c index d41b84320..6a061fed0 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -366,22 +366,28 @@ void HandleAction_UseItem(void) bool8 TryRunFromBattle(u8 battler) { - bool8 effect = FALSE; + bool32 effect = FALSE; u8 holdEffect; u8 speedVar; - if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY) + if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY_E_READER) holdEffect = gEnigmaBerries[battler].holdEffect; else holdEffect = ItemId_GetHoldEffect(gBattleMons[battler].item); + gPotentialItemEffectBattler = battler; + if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) { gLastUsedItem = gBattleMons[battler].item; gProtectStructs[battler].fleeType = FLEE_ITEM; effect++; } - else if (gBattleMons[battler].ability == ABILITY_RUN_AWAY) + else if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) + { + effect++; + } + else if (GetBattlerAbility(battler) == ABILITY_RUN_AWAY) { gLastUsedAbility = ABILITY_RUN_AWAY; gProtectStructs[battler].fleeType = FLEE_ABILITY; @@ -394,27 +400,30 @@ bool8 TryRunFromBattle(u8 battler) } else { - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + u8 runningFromBattler = BATTLE_OPPOSITE(battler); + if (!IsBattlerAlive(runningFromBattler)) + runningFromBattler |= BIT_FLANK; + + if (gBattleMons[battler].speed < gBattleMons[runningFromBattler].speed) { - if (gBattleMons[battler].speed < gBattleMons[BATTLE_OPPOSITE(battler)].speed) - { - speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30); - if (speedVar > (Random() & 0xFF)) - effect++; - } - else // same speed or faster - { + speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[runningFromBattler].speed) + (gBattleStruct->runTries * 30); + if (speedVar > (Random() & 0xFF)) effect++; - } + } + else // same speed or faster + { + effect++; } - ++gBattleStruct->runTries; + gBattleStruct->runTries++; } + if (effect != 0) { gCurrentTurnActionNumber = gBattlersCount; gBattleOutcome = B_OUTCOME_RAN; } + return effect; } diff --git a/src/party_menu.c b/src/party_menu.c index 18bdb52be..e4bef1d29 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -6325,10 +6325,10 @@ void ChooseMonForWirelessMinigame(void) static u8 GetPartyLayoutFromBattleType(void) { - if (IsDoubleBattle() == FALSE) - return PARTY_LAYOUT_SINGLE; if (IsMultiBattle() == TRUE) return PARTY_LAYOUT_MULTI; + if (!IsDoubleBattle() || gPlayerPartyCount == 1) + return PARTY_LAYOUT_SINGLE; return PARTY_LAYOUT_DOUBLE; } @@ -6578,12 +6578,12 @@ static void BufferBattlePartyOrderBySide(u8 *partyBattleOrder, u8 flankId, u8 ba { j = 1; partyIndexes[0] = gBattlerPartyIndexes[leftBattler]; - for (i = 0; i < PARTY_SIZE; ++i) + for (i = 0; i < PARTY_SIZE; i++) { if (i != partyIndexes[0]) { partyIndexes[j] = i; - ++j; + j++; } } } @@ -6592,16 +6592,16 @@ static void BufferBattlePartyOrderBySide(u8 *partyBattleOrder, u8 flankId, u8 ba j = 2; partyIndexes[0] = gBattlerPartyIndexes[leftBattler]; partyIndexes[1] = gBattlerPartyIndexes[rightBattler]; - for (i = 0; i < PARTY_SIZE; ++i) + for (i = 0; i < PARTY_SIZE; i++) { if (i != partyIndexes[0] && i != partyIndexes[1]) { partyIndexes[j] = i; - ++j; + j++; } } } - for (i = 0; i < 3; ++i) + for (i = 0; i < 3; i++) partyBattleOrder[i] = (partyIndexes[0 + (i * 2)] << 4) | partyIndexes[1 + (i * 2)]; } diff --git a/src/pokeball.c b/src/pokeball.c index 04e6c2dc6..e9661edd6 100644 --- a/src/pokeball.c +++ b/src/pokeball.c @@ -672,8 +672,10 @@ static void SpriteCB_BallThrow_Shake(struct Sprite *sprite) #define tCryTaskSpecies data[0] #define tCryTaskPan data[1] #define tCryTaskWantedCry data[2] -#define tCryTaskMonPtr1 data[3] -#define tCryTaskMonPtr2 data[4] +#define tCryTaskBattler data[3] +#define tCryTaskMonSpriteId data[4] +#define tCryTaskMonPtr1 data[5] +#define tCryTaskMonPtr2 data[6] #define tCryTaskFrames data[10] #define tCryTaskState data[15] @@ -682,15 +684,15 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId) u8 wantedCry = gTasks[taskId].tCryTaskWantedCry; s8 pan = gTasks[taskId].tCryTaskPan; u16 species = gTasks[taskId].tCryTaskSpecies; + u8 battlerId = gTasks[taskId].tCryTaskBattler; + u8 monSpriteId = gTasks[taskId].tCryTaskMonSpriteId; struct Pokemon *mon = (void *)(u32)((gTasks[taskId].tCryTaskMonPtr1 << 16) | (u16)(gTasks[taskId].tCryTaskMonPtr2)); switch (gTasks[taskId].tCryTaskState) { case 0: default: - if (gTasks[taskId].data[8] < 3) - gTasks[taskId].data[8]++; - else + if (gSprites[monSpriteId].affineAnimEnded) gTasks[taskId].tCryTaskState = wantedCry + 1; break; case 1: @@ -699,7 +701,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId) PlayCry_ByMode(species, pan, CRY_MODE_NORMAL); else PlayCry_ByMode(species, pan, CRY_MODE_WEAK); - + gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = FALSE; DestroyTask(taskId); break; case 2: @@ -716,6 +718,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId) else PlayCry_ReleaseDouble(species, pan, CRY_MODE_WEAK_DOUBLES); + gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = FALSE; DestroyTask(taskId); } else @@ -755,6 +758,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId) else PlayCry_ReleaseDouble(species, pan, CRY_MODE_WEAK); + gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = FALSE; DestroyTask(taskId); break; } @@ -773,7 +777,7 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite) if (gMain.inBattle) { - struct Pokemon *mon; + struct Pokemon *mon, *illusionMon; u16 species; s8 pan; u16 wantedCryCase; @@ -812,10 +816,20 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite) else wantedCryCase = 2; + gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = TRUE; + taskId = CreateTask(Task_PlayCryWhenReleasedFromBall, 3); - gTasks[taskId].tCryTaskSpecies = species; + + illusionMon = GetIllusionMonPtr(battlerId); + if (illusionMon != NULL) + gTasks[taskId].tCryTaskSpecies = GetMonData(illusionMon, MON_DATA_SPECIES); + else + gTasks[taskId].tCryTaskSpecies = GetMonData(mon, MON_DATA_SPECIES); + gTasks[taskId].tCryTaskPan = pan; gTasks[taskId].tCryTaskWantedCry = wantedCryCase; + gTasks[taskId].tCryTaskBattler = battlerId; + gTasks[taskId].tCryTaskMonSpriteId = gBattlerSpriteIds[sprite->sBattler]; gTasks[taskId].tCryTaskMonPtr1 = (u32)(mon) >> 16; gTasks[taskId].tCryTaskMonPtr2 = (u32)(mon); gTasks[taskId].tCryTaskState = 0; @@ -829,6 +843,8 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite) #undef tCryTaskSpecies #undef tCryTaskPan #undef tCryTaskWantedCry +#undef tCryTaskBattler +#undef tCryTaskMonSpriteId #undef tCryTaskMonPtr1 #undef tCryTaskMonPtr2 #undef tCryTaskFrames diff --git a/src/pokemon.c b/src/pokemon.c index 0e227783c..074dcabb9 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -5317,13 +5317,6 @@ u16 SpeciesToPokedexNum(u16 species) return species > 0 ? species : 0xFFFF; } -void ClearBattleMonForms(void) -{ - int i; - for (i = 0; i < MAX_BATTLERS_COUNT; i++) - gBattleMonForms[i] = 0; -} - static u16 GetBattleBGM(void) { if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON) diff --git a/src/reshow_battle_screen.c b/src/reshow_battle_screen.c index 7ff849ee9..f43a22daf 100644 --- a/src/reshow_battle_screen.c +++ b/src/reshow_battle_screen.c @@ -236,7 +236,7 @@ static void CreateBattlerSprite(u8 battler) gSprites[gBattlerSpriteIds[battler]].callback = SpriteCallbackDummy; gSprites[gBattlerSpriteIds[battler]].data[0] = battler; gSprites[gBattlerSpriteIds[battler]].data[2] = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES); - StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], gBattleMonForms[battler]); + StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], 0); } else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI && battler == B_POSITION_PLAYER_LEFT) { @@ -270,7 +270,7 @@ static void CreateBattlerSprite(u8 battler) gSprites[gBattlerSpriteIds[battler]].callback = SpriteCallbackDummy; gSprites[gBattlerSpriteIds[battler]].data[0] = battler; gSprites[gBattlerSpriteIds[battler]].data[2] = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES); - StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], gBattleMonForms[battler]); + StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], 0); } gSprites[gBattlerSpriteIds[battler]].invisible = gBattleSpritesDataPtr->battlerData[battler].invisible; } @@ -306,9 +306,10 @@ static void CreateHealthboxSprite(u8 battler) if (GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_HP) == 0) SetHealthboxSpriteInvisible(healthboxSpriteId); } - else if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI) && GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_HP) == 0) - { - SetHealthboxSpriteInvisible(healthboxSpriteId); + else if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) + { + if (!IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[battler]])) + SetHealthboxSpriteInvisible(healthboxSpriteId); } } } diff --git a/src/text.c b/src/text.c index 76739f8c6..a196ca33d 100644 --- a/src/text.c +++ b/src/text.c @@ -1179,7 +1179,7 @@ s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing) return width; } -u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str, int a3, int a4, int a5, int a6, int a7) +u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str) { u8 shadowColor; u8 *strLocal; diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 15d66cf8e..07e68c198 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -13,6 +13,7 @@ #include "script.h" #include "link.h" #include "quest_log.h" +#include "safari_zone.h" #include "constants/maps.h" #include "constants/abilities.h" #include "constants/items.h" @@ -394,7 +395,17 @@ bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetatileBehavior) // try a regular wild land encounter if (TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_REPEL) == TRUE) { - StartWildBattle(); + if (TryDoDoubleWildBattle()) + { + struct Pokemon mon1 = gEnemyParty[0]; + TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE); + gEnemyParty[1] = mon1; + StartDoubleWildBattle(); + } + else + { + StartWildBattle(); + } return TRUE; } else @@ -432,7 +443,17 @@ bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetatileBehavior) if (TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL) == TRUE) { gIsSurfingEncounter = TRUE; - StartWildBattle(); + if (TryDoDoubleWildBattle()) + { + struct Pokemon mon1 = gEnemyParty[0]; + TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_KEEN_EYE); + gEnemyParty[1] = mon1; + StartDoubleWildBattle(); + } + else + { + StartWildBattle(); + } return TRUE; } else @@ -786,3 +807,15 @@ static void AddToWildEncounterRateBuff(u8 encounterRate) else sWildEncounterData.encounterRateBuff = 0; } + +bool8 TryDoDoubleWildBattle(void) +{ + if (GetSafariZoneFlag() + || (B_DOUBLE_WILD_REQUIRE_2_MONS == TRUE && GetMonsStateToDoubles() != PLAYER_HAS_TWO_USABLE_MONS)) + return FALSE; + else if (B_FLAG_FORCE_DOUBLE_WILD != 0 && FlagGet(B_FLAG_FORCE_DOUBLE_WILD)) + return TRUE; + else if (B_DOUBLE_WILD_CHANCE != 0 && ((Random() % 100) + 1 <= B_DOUBLE_WILD_CHANCE)) + return TRUE; + return FALSE; +}