From eac81356872713024694368109da02b16a4976fb Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 10 Dec 2020 21:37:37 -0700 Subject: [PATCH 01/36] set up ai c function table --- src/battle_ai_script_commands.c | 128 +++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 8a5f423a4e..22b1df3d56 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -187,6 +187,55 @@ EWRAM_DATA static u8 sBattler_AI = 0; // const rom data typedef void (*BattleAICmdFunc)(void); +static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); + +static u8 (*const sBattleAiFuncTable[])(u8, u8, u16, u8) = +{ + [0] = AI_CheckBadMove, // AI_SCRIPT_CHECK_BAD_MOVE + [1] = AI_TryToFaint, // AI_SCRIPT_TRY_TO_FAINT + [2] = AI_CheckViability, // AI_SCRIPT_CHECK_VIABILITY + [3] = AI_SetupFirstTurn, // AI_SCRIPT_SETUP_FIRST_TURN + [4] = AI_Risky, // AI_SCRIPT_RISKY + [5] = AI_PreferStrongestMove, // AI_SCRIPT_PREFER_STRONGEST_MOVE + [6] = AI_PreferBatonPass, // AI_SCRIPT_PREFER_BATON_PASS + [7] = AI_DoubleBattle, // AI_SCRIPT_DOUBLE_BATTLE + [8] = AI_HPAware, // AI_SCRIPT_HP_AWARE + [9] = NULL, // Unused + [10] = NULL, // Unused + [11] = NULL, // Unused + [12] = NULL, // Unused + [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_SCRIPT_ROAMING + [30] = AI_Safari, // AI_SCRIPT_SAFARI + [31] = AI_FirstBattle, // AI_SCRIPT_FIRST_BATTLE +}; + static const BattleAICmdFunc sBattleAICmdTable[] = { Cmd_if_random_less_than, // 0x0 @@ -711,9 +760,17 @@ static void BattleAI_DoAIProcessing(void) AI_THINKING_STRUCT->aiState++; break; case AIState_Processing: - if (AI_THINKING_STRUCT->moveConsidered != 0) - { - sBattleAICmdTable[*gAIScriptPtr](); // Run AI command. + if (AI_THINKING_STRUCT->moveConsidered != MOVE_NONE + && AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] > 0) + { + if (AI_THINKING_STRUCT->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable) + && sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId] != NULL) + { + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId](gBattlerAttacker, + gBattlerTarget, + AI_THINKING_STRUCT->moveConsidered, + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex]); //Run AI script + } } else { @@ -2869,3 +2926,68 @@ static void Cmd_if_has_move_with_accuracy_lt(void) else gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); } + + + + + + +// AI Functions +static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ +} + +static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +{ + +} + + + + + + + + + + From aad3a800c3adf9c429f489d3c6db90972bfdaba3 Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 10 Dec 2020 22:10:21 -0700 Subject: [PATCH 02/36] c functions for ai roamers/safari/first battle --- data/battle_ai_scripts.s | 64 +--------------------------- include/battle_ai_util.h | 8 ++++ ld_script.txt | 1 + src/battle_ai_script_commands.c | 75 ++++++++++++++++++++++----------- src/battle_ai_util.c | 47 +++++++++++++++++++++ 5 files changed, 108 insertions(+), 87 deletions(-) create mode 100644 include/battle_ai_util.h create mode 100644 src/battle_ai_util.c diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index 17238670d0..9e504dd55e 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -21,29 +21,7 @@ gBattleAI_ScriptsTable:: @ 82DBEF8 .4byte AI_PreferBatonPass @ AI_SCRIPT_PREFER_BATON_PASS .4byte AI_DoubleBattle @ AI_SCRIPT_DOUBLE_BATTLE .4byte AI_HPAware @ AI_SCRIPT_HP_AWARE - .4byte AI_Unknown @ AI_SCRIPT_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 @ AI_SCRIPT_ROAMING - .4byte AI_Safari @ AI_SCRIPT_SAFARI - .4byte AI_FirstBattle @ AI_SCRIPT_FIRST_BATTLE + AI_CheckBadMove: if_target_is_ally AI_Ret @@ -4140,47 +4118,7 @@ AI_HPAware_DiscouragedEffectsWhenTargetLowHP: @ 82DE2B1 .byte EFFECT_DRAGON_DANCE .byte -1 -AI_Unknown: - if_target_is_ally AI_TryOnAlly - 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: @ 82DE308 - 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: @ 82DE335 - flee - -AI_Roaming_End: @ 82DE336 - end - -AI_Safari: - if_random_safari_flee AI_Safari_Flee - watch - -AI_Safari_Flee: - flee - -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_ai_util.h b/include/battle_ai_util.h new file mode 100644 index 0000000000..2772c66216 --- /dev/null +++ b/include/battle_ai_util.h @@ -0,0 +1,8 @@ +#ifndef GUARD_BATTLE_AI_UTIL_H +#define GUARD_BATTLE_AI_UTIL_H + +u32 GetHealthPercentage(u8 battler); +bool32 IsBattlerTrapped(u8 battler, bool8 switching); + + +#endif //GUARD_BATTLE_AI_UTIL_H \ No newline at end of file diff --git a/ld_script.txt b/ld_script.txt index 091b6e693c..2bf411e627 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -214,6 +214,7 @@ SECTIONS { src/slot_machine.o(.text); src/contest_painting.o(.text); src/battle_ai_script_commands.o(.text); + src/battle_ai_util.o(.text); src/trader.o(.text); src/starter_choose.o(.text); src/wallclock.o(.text); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 22b1df3d56..695844bb28 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -2,6 +2,7 @@ #include "malloc.h" #include "battle.h" #include "battle_anim.h" +#include "battle_ai_util.h" #include "battle_ai_script_commands.h" #include "battle_factory.h" #include "battle_setup.h" @@ -187,18 +188,18 @@ EWRAM_DATA static u8 sBattler_AI = 0; // const rom data typedef void (*BattleAICmdFunc)(void); -static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); static u8 (*const sBattleAiFuncTable[])(u8, u8, u16, u8) = { @@ -2933,53 +2934,79 @@ static void Cmd_if_has_move_with_accuracy_lt(void) // AI Functions -static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static void AI_Flee(void) { + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); } -static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static void AI_Watch(void) { + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); } -static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { + if (IsBattlerTrapped(battlerAtk, FALSE)) + return originalScore; + AI_Flee(); + return originalScore; +} + +static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +{ + u8 safariFleeRate = gBattleStruct->safariEscapeFactor * 5; // Safari flee rate, from 0-20. + + if ((Random() % 100) < safariFleeRate) + AI_Flee(); + else + AI_Watch(); + + return originalScore; +} + +static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +{ + if (GetHealthPercentage(battlerDef) <= 20) + AI_Flee(); + + return originalScore; } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c new file mode 100644 index 0000000000..8b9778668c --- /dev/null +++ b/src/battle_ai_util.c @@ -0,0 +1,47 @@ +#include "global.h" +#include "malloc.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_ai_util.h" +#include "battle_ai_script_commands.h" +#include "battle_factory.h" +#include "battle_setup.h" +#include "data.h" +#include "item.h" +#include "pokemon.h" +#include "random.h" +#include "recorded_battle.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" + +// Functions +u32 GetHealthPercentage(u8 battlerId) +{ + return (u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP); +} + +bool32 IsBattlerTrapped(u8 battler, bool8 switching) +{ + u8 holdEffect = GetBattlerHoldEffect(battler, TRUE); + if (IS_BATTLER_OF_TYPE(battler, TYPE_GHOST) + || (switching && holdEffect == HOLD_EFFECT_SHED_SHELL) + || (!switching && GetBattlerAbility(battler) == ABILITY_RUN_AWAY) + || (!switching && holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)) + { + return FALSE; + } + else + { + if (gBattleMons[battler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED) + || IsAbilityPreventingEscape(battler) + || gStatuses3[battler] & (STATUS3_ROOTED) // TODO: sky drop target in air + || (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK)) + return TRUE; + } + + return FALSE; +} \ No newline at end of file From 28698a982d0e936e178dc1ccf32e4b6da2469764 Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 11 Dec 2020 08:05:00 -0700 Subject: [PATCH 03/36] try to faint script -> c --- include/battle.h | 3 + include/battle_ai_script_commands.h | 2 + include/battle_ai_util.h | 24 +- ld_script.txt | 1 + src/battle_ai_script_commands.c | 475 +++------------------------- src/battle_ai_util.c | 443 +++++++++++++++++++++++++- 6 files changed, 518 insertions(+), 430 deletions(-) diff --git a/include/battle.h b/include/battle.h index a6e201a239..17fd49e7ea 100644 --- a/include/battle.h +++ b/include/battle.h @@ -294,6 +294,9 @@ struct BattleResources u8 bufferB[MAX_BATTLERS_COUNT][0x200]; }; +#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) +#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) + struct BattleResults { u8 playerFaintCounter; // 0x0 diff --git a/include/battle_ai_script_commands.h b/include/battle_ai_script_commands.h index be37873980..eb57d613f4 100644 --- a/include/battle_ai_script_commands.h +++ b/include/battle_ai_script_commands.h @@ -24,4 +24,6 @@ void ClearBattlerAbilityHistory(u8 battlerId); void RecordItemEffectBattle(u8 battlerId, u8 itemEffect); void ClearBattlerItemEffectHistory(u8 battlerId); +extern u8 sBattler_AI; + #endif // GUARD_BATTLE_AI_SCRIPT_COMMANDS_H diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 2772c66216..dd9fe2a8a1 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -1,8 +1,30 @@ #ifndef GUARD_BATTLE_AI_UTIL_H #define GUARD_BATTLE_AI_UTIL_H +// for IsBattlerFaster +#define AI_CHECK_FASTER 0 // if_user_faster +#define AI_CHECK_SLOWER 1 // if_target_faster + +void RecordLastUsedMoveByTarget(void); +bool32 IsBattlerAIControlled(u32 battlerId); +void ClearBattlerMoveHistory(u8 battlerId); +void RecordLastUsedMoveBy(u32 battlerId, u32 move); +void RecordKnownMove(u8 battlerId, u32 move); +void RecordAbilityBattle(u8 battlerId, u16 abilityId); +void ClearBattlerAbilityHistory(u8 battlerId); +void RecordItemEffectBattle(u8 battlerId, u8 itemEffect); +void ClearBattlerItemEffectHistory(u8 battlerId); +void SaveBattlerData(u8 battlerId); +void SetBattlerData(u8 battlerId); +void RestoreBattlerData(u8 battlerId); + u32 GetHealthPercentage(u8 battler); bool32 IsBattlerTrapped(u8 battler, bool8 switching); - +u8 GetMovePowerResult(u16 move); +u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); +u8 GetMoveEffectiveness(u16 move); +bool32 IsBattlerFaster(u8 battler); +bool32 CanTargetFaintAi(void); +s32 AI_GetAbility(u32 battlerId, bool32 guess); #endif //GUARD_BATTLE_AI_UTIL_H \ No newline at end of file diff --git a/ld_script.txt b/ld_script.txt index 2bf411e627..c6276922a9 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -590,6 +590,7 @@ SECTIONS { src/slot_machine.o(.rodata); src/contest_painting.o(.rodata); src/battle_ai_script_commands.o(.rodata); + src/battle_ai_util.o(.rodata); src/trader.o(.rodata); src/starter_choose.o(.rodata); src/wallclock.o(.rodata); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 695844bb28..1e0b414d07 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -27,9 +27,6 @@ #define AI_ACTION_UNK7 0x0040 #define AI_ACTION_UNK8 0x0080 -#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) -#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) - // AI states enum { @@ -51,12 +48,10 @@ extern const u8 *const gBattleAI_ScriptsTable[]; static u8 ChooseMoveOrAction_Singles(void); static u8 ChooseMoveOrAction_Doubles(void); -static void RecordLastUsedMoveByTarget(void); static void BattleAI_DoAIProcessing(void); static void AIStackPushVar(const u8 *); static bool8 AIStackPop(void); static s32 CountUsablePartyMons(u8 battlerId); -static s32 AI_GetAbility(u32 battlerId, bool32 guess); static void Cmd_if_random_less_than(void); static void Cmd_if_random_greater_than(void); @@ -183,7 +178,7 @@ static void Cmd_if_has_move_with_accuracy_lt(void); // ewram EWRAM_DATA const u8 *gAIScriptPtr = NULL; -EWRAM_DATA static u8 sBattler_AI = 0; +EWRAM_DATA u8 sBattler_AI = 0; // const rom data typedef void (*BattleAICmdFunc)(void); @@ -363,22 +358,6 @@ static const BattleAICmdFunc sBattleAICmdTable[] = Cmd_if_has_move_with_accuracy_lt, // 0x79 }; -static const u16 sDiscouragedPowerfulMoveEffects[] = -{ - EFFECT_EXPLOSION, - EFFECT_DREAM_EATER, - EFFECT_RECHARGE, - EFFECT_SKULL_BASH, - EFFECT_SOLARBEAM, - EFFECT_SPIT_UP, - EFFECT_FOCUS_PUNCH, - EFFECT_SUPERPOWER, - EFFECT_ERUPTION, - EFFECT_OVERHEAT, - EFFECT_MIND_BLOWN, - 0xFFFF -}; - // code void BattleAI_SetupItems(void) { @@ -794,139 +773,6 @@ static void BattleAI_DoAIProcessing(void) } } -static void RecordLastUsedMoveByTarget(void) -{ - RecordKnownMove(gBattlerTarget, gLastMoves[gBattlerTarget]); -} - -bool32 IsBattlerAIControlled(u32 battlerId) -{ - switch (GetBattlerPosition(battlerId)) - { - case B_POSITION_PLAYER_LEFT: - default: - return FALSE; - case B_POSITION_OPPONENT_LEFT: - return TRUE; - case B_POSITION_PLAYER_RIGHT: - return ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) != 0); - case B_POSITION_OPPONENT_RIGHT: - return TRUE; - } -} - -void ClearBattlerMoveHistory(u8 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(u8 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; - break; - } - } -} - -void RecordAbilityBattle(u8 battlerId, u16 abilityId) -{ - BATTLE_HISTORY->abilities[battlerId] = abilityId; -} - -void ClearBattlerAbilityHistory(u8 battlerId) -{ - BATTLE_HISTORY->abilities[battlerId] = ABILITY_NONE; -} - -void RecordItemEffectBattle(u8 battlerId, u8 itemEffect) -{ - BATTLE_HISTORY->itemEffects[battlerId] = itemEffect; -} - -void ClearBattlerItemEffectHistory(u8 battlerId) -{ - BATTLE_HISTORY->itemEffects[battlerId] = 0; -} - -static void SaveBattlerData(u8 battlerId) -{ - if (!IsBattlerAIControlled(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]; - } -} - -static void SetBattlerData(u8 battlerId) -{ - if (!IsBattlerAIControlled(battlerId)) - { - struct Pokemon *illusionMon; - u32 i; - - // Use the known battler's ability. - if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE) - gBattleMons[battlerId].ability = BATTLE_HISTORY->abilities[battlerId]; - // Check if mon can only have one ability. - else if (gBaseStats[gBattleMons[battlerId].species].abilities[1] == ABILITY_NONE - || gBaseStats[gBattleMons[battlerId].species].abilities[1] == gBaseStats[gBattleMons[battlerId].species].abilities[0]) - gBattleMons[battlerId].ability = gBaseStats[gBattleMons[battlerId].species].abilities[0]; - // The ability is unknown. - else - gBattleMons[battlerId].ability = ABILITY_NONE; - - if (BATTLE_HISTORY->itemEffects[battlerId] == 0) - gBattleMons[battlerId].item = 0; - - for (i = 0; i < 4; i++) - { - if (BATTLE_HISTORY->usedMoves[battlerId][i] == 0) - gBattleMons[battlerId].moves[i] = 0; - } - - // Simulate Illusion - if ((illusionMon = GetIllusionMonPtr(battlerId)) != NULL) - gBattleMons[battlerId].species = GetMonData(illusionMon, MON_DATA_SPECIES2); - } -} - -static void RestoreBattlerData(u8 battlerId) -{ - if (!IsBattlerAIControlled(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]; - } -} - static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef) { bool32 isCrit; @@ -1003,27 +849,6 @@ s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon return dmg; } -u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) -{ - u16 typeEffectiveness, 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, FALSE); - - RestoreBattlerData(battlerAtk); - RestoreBattlerData(battlerDef); - - return typeEffectiveness; -} - static void Cmd_if_random_less_than(void) { u16 random = Random(); @@ -1459,141 +1284,11 @@ static void Cmd_get_considered_move_power(void) gAIScriptPtr += 1; } -// Checks if one of the moves has side effects or perks -static u32 WhichMoveBetter(u32 move1, u32 move2) -{ - s32 defAbility = AI_GetAbility(gBattlerTarget, FALSE); - // Check if physical moves hurt. - if (GetBattlerHoldEffect(sBattler_AI, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && (BATTLE_HISTORY->itemEffects[gBattlerTarget] == 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 recoil - if (GetBattlerAbility(sBattler_AI) != ABILITY_ROCK_HEAD) - { - if (((gBattleMoves[move1].effect == EFFECT_RECOIL_25 - || gBattleMoves[move1].effect == EFFECT_RECOIL_IF_MISS - || gBattleMoves[move1].effect == EFFECT_RECOIL_50 - || gBattleMoves[move1].effect == EFFECT_RECOIL_33 - || gBattleMoves[move1].effect == EFFECT_RECOIL_33_STATUS) - && (gBattleMoves[move2].effect != EFFECT_RECOIL_25 - && gBattleMoves[move2].effect != EFFECT_RECOIL_IF_MISS - && gBattleMoves[move2].effect != EFFECT_RECOIL_50 - && gBattleMoves[move2].effect != EFFECT_RECOIL_33 - && gBattleMoves[move2].effect != EFFECT_RECOIL_33_STATUS - && gBattleMoves[move2].effect != EFFECT_RECHARGE))) - return 1; - - if (((gBattleMoves[move2].effect == EFFECT_RECOIL_25 - || gBattleMoves[move2].effect == EFFECT_RECOIL_IF_MISS - || gBattleMoves[move2].effect == EFFECT_RECOIL_50 - || gBattleMoves[move2].effect == EFFECT_RECOIL_33 - || gBattleMoves[move2].effect == EFFECT_RECOIL_33_STATUS) - && (gBattleMoves[move1].effect != EFFECT_RECOIL_25 - && gBattleMoves[move1].effect != EFFECT_RECOIL_IF_MISS - && gBattleMoves[move1].effect != EFFECT_RECOIL_50 - && gBattleMoves[move1].effect != EFFECT_RECOIL_33 - && gBattleMoves[move1].effect != EFFECT_RECOIL_33_STATUS - && gBattleMoves[move1].effect != EFFECT_RECHARGE))) - return 0; - } - // Check recharge - if (gBattleMoves[move1].effect == EFFECT_RECHARGE && gBattleMoves[move2].effect != EFFECT_RECHARGE) - return 1; - if (gBattleMoves[move2].effect == EFFECT_RECHARGE && gBattleMoves[move1].effect != EFFECT_RECHARGE) - return 0; - // Check additional effect. - if (gBattleMoves[move1].effect == 0 && gBattleMoves[move2].effect != 0) - return 1; - if (gBattleMoves[move2].effect == 0 && gBattleMoves[move1].effect != 0) - return 0; - - return 2; -} static void Cmd_get_how_powerful_move_is(void) { - s32 i, checkedMove, bestId, currId, hp; - s32 moveDmgs[MAX_MON_MOVES]; - - for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) - { - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect == sDiscouragedPowerfulMoveEffects[i]) - break; - } - - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power != 0 - && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF) - { - for (checkedMove = 0; checkedMove < MAX_MON_MOVES; checkedMove++) - { - for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) - { - if (gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].effect == sDiscouragedPowerfulMoveEffects[i]) - break; - } - - if (gBattleMons[sBattler_AI].moves[checkedMove] != MOVE_NONE - && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF - && gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].power != 0) - { - moveDmgs[checkedMove] = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][checkedMove]; - } - else - { - moveDmgs[checkedMove] = 0; - } - } - - hp = gBattleMons[gBattlerTarget].hp + (20 * gBattleMons[gBattlerTarget].hp / 100); // 20 % add to make sure the battler is always fainted - // If a move can faint battler, it doesn't matter how much damage it does - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (moveDmgs[i] > hp) - moveDmgs[i] = hp; - } - - for (bestId = 0, i = 1; i < MAX_MON_MOVES; i++) - { - if (moveDmgs[i] > moveDmgs[bestId]) - bestId = i; - if (moveDmgs[i] == moveDmgs[bestId]) - { - switch (WhichMoveBetter(gBattleMons[sBattler_AI].moves[bestId], gBattleMons[sBattler_AI].moves[i])) - { - case 2: - if (Random() & 1) - break; - case 1: - bestId = i; - break; - } - } - } - - currId = AI_THINKING_STRUCT->movesetIndex; - if (currId == bestId) - AI_THINKING_STRUCT->funcResult = MOVE_POWER_BEST; - // Compare percentage difference. - else if ((moveDmgs[currId] >= hp || moveDmgs[bestId] < hp) // If current move can faint as well, or if neither can - && (moveDmgs[bestId] * 100 / hp) - (moveDmgs[currId] * 100 / hp) <= 30 - && WhichMoveBetter(gBattleMons[sBattler_AI].moves[bestId], gBattleMons[sBattler_AI].moves[currId]) != 0) - AI_THINKING_STRUCT->funcResult = MOVE_POWER_GOOD; - else - AI_THINKING_STRUCT->funcResult = MOVE_POWER_WEAK; - } - else - { - AI_THINKING_STRUCT->funcResult = MOVE_POWER_DISCOURAGED; // Highly discouraged in terms of power. - } - - gAIScriptPtr++; + // GetMovePowerResult } static void Cmd_get_last_used_battler_move(void) @@ -1620,48 +1315,7 @@ static void Cmd_if_not_equal_u32(void) static void Cmd_if_user_goes(void) { - u32 fasterAI = 0, fasterPlayer = 0, i; - s8 prioAI, prioPlayer; - - // Check move priorities first. - prioAI = GetMovePriority(sBattler_AI, AI_THINKING_STRUCT->moveConsidered); - SaveBattlerData(gBattlerTarget); - SetBattlerData(gBattlerTarget); - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[gBattlerTarget].moves[i] == 0 || gBattleMons[gBattlerTarget].moves[i] == 0xFFFF) - continue; - - prioPlayer = GetMovePriority(gBattlerTarget, gBattleMons[gBattlerTarget].moves[i]); - if (prioAI > prioPlayer) - fasterAI++; - else if (prioPlayer > prioAI) - fasterPlayer++; - } - RestoreBattlerData(gBattlerTarget); - - if (fasterAI > fasterPlayer) - { - if (gAIScriptPtr[1] == 0) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; - } - else if (fasterAI < fasterPlayer) - { - if (gAIScriptPtr[1] == 1) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; - } - else - { - // Priorities are the same(at least comparing to moves the AI is aware of), decide by speed. - if (GetWhoStrikesFirst(sBattler_AI, gBattlerTarget, TRUE) == gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; - } + // IsBattlerFaster } static void Cmd_nullsub_2A(void) @@ -1726,37 +1380,6 @@ static void Cmd_get_considered_move_effect(void) gAIScriptPtr += 1; } -static s32 AI_GetAbility(u32 battlerId, bool32 guess) -{ - // The AI knows its own ability. - if (IsBattlerAIControlled(battlerId)) - return gBattleMons[battlerId].ability; - - if (BATTLE_HISTORY->abilities[battlerId] != 0) - return BATTLE_HISTORY->abilities[battlerId]; - - // Abilities that prevent fleeing. - if (gBattleMons[battlerId].ability == ABILITY_SHADOW_TAG - || gBattleMons[battlerId].ability == ABILITY_MAGNET_PULL - || gBattleMons[battlerId].ability == ABILITY_ARENA_TRAP) - return gBattleMons[battlerId].ability; - - if (gBaseStats[gBattleMons[battlerId].species].abilities[0] != ABILITY_NONE) - { - if (gBaseStats[gBattleMons[battlerId].species].abilities[1] != ABILITY_NONE) - { - // AI has no knowledge of opponent, so it guesses which ability. - if (guess) - return gBaseStats[gBattleMons[battlerId].species].abilities[Random() & 1]; - } - else - { - return gBaseStats[gBattleMons[battlerId].species].abilities[0]; // It's definitely ability 1. - } - } - return -1; // Unknown. -} - static void Cmd_get_ability(void) { AI_THINKING_STRUCT->funcResult = AI_GetAbility(BattleAI_GetWantedBattler(gAIScriptPtr[1]), TRUE); @@ -1824,39 +1447,7 @@ static void Cmd_get_highest_type_effectiveness(void) static void Cmd_if_type_effectiveness(void) { - u8 damageVar; - u32 effectivenessMultiplier; - - gMoveResultFlags = 0; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, sBattler_AI, gBattlerTarget); - switch (effectivenessMultiplier) - { - case UQ_4_12(0.0): - default: - damageVar = AI_EFFECTIVENESS_x0; - break; - case UQ_4_12(0.25): - damageVar = AI_EFFECTIVENESS_x0_25; - break; - case UQ_4_12(0.5): - damageVar = AI_EFFECTIVENESS_x0_5; - break; - case UQ_4_12(1.0): - damageVar = AI_EFFECTIVENESS_x1; - break; - case UQ_4_12(2.0): - damageVar = AI_EFFECTIVENESS_x2; - break; - case UQ_4_12(4.0): - damageVar = AI_EFFECTIVENESS_x4; - break; - } - - if (damageVar == gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; + // GetMoveEffectiveness } static void Cmd_nullsub_32(void) @@ -2725,21 +2316,7 @@ static void Cmd_if_physical_moves_unusable(void) // Check if target has means to faint ai mon. static void Cmd_if_ai_can_go_down(void) { - s32 i, dmg; - u32 unusable = CheckMoveLimitations(gBattlerTarget, 0, 0xFF & ~MOVE_LIMITATION_PP); - u16 *moves = gBattleResources->battleHistory->usedMoves[gBattlerTarget]; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i]) - && AI_CalcDamage(moves[i], gBattlerTarget, sBattler_AI) >= gBattleMons[sBattler_AI].hp) - { - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); - return; - } - } - - gAIScriptPtr += 5; + // CanTargetFaintAi } static void Cmd_if_cant_use_belch(void) @@ -2940,6 +2517,48 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { + s32 dmg; + u8 result; + u8 score = originalScore; + + if (GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef)) + return originalScore; // don't try to faint your ally + + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power == 0) + return originalScore; // can't make anything faint with no power + + dmg = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][AI_THINKING_STRUCT->movesetIndex]; + if (gBattleMons[gBattlerTarget].hp <= dmg && gBattleMoves[move].effect != EFFECT_EXPLOSION) + { + // AI_TryToFaint_Can + if (IsBattlerFaster(AI_CHECK_FASTER) || gBattleMoves[move].flags & FLAG_HIGH_CRIT) + score += 4; + else + score += 2; + } + else + { + if (GetMovePowerResult(move) == MOVE_POWER_DISCOURAGED) + return (score - 1); + + if (GetMoveEffectiveness(move) == AI_EFFECTIVENESS_x4) + { + // AI_TryToFaint_DoubleSuperEffective + if ((Random() % 256) >= 80) + score += 2; + } + } + + //AI_TryToFaint_CheckIfDanger + if (!IsBattlerFaster(AI_CHECK_FASTER) && CanTargetFaintAi()) + { // AI_TryToFaint_Danger + if (GetMovePowerResult(move) != MOVE_POWER_BEST) + score--; + else + score++; + } + + return score; } static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 8b9778668c..3a62c02b54 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -18,7 +18,157 @@ #include "constants/hold_effects.h" #include "constants/moves.h" +// Const Data +static const u16 sDiscouragedPowerfulMoveEffects[] = +{ + EFFECT_EXPLOSION, + EFFECT_DREAM_EATER, + EFFECT_RECHARGE, + EFFECT_SKULL_BASH, + EFFECT_SOLARBEAM, + EFFECT_SPIT_UP, + EFFECT_FOCUS_PUNCH, + EFFECT_SUPERPOWER, + EFFECT_ERUPTION, + EFFECT_OVERHEAT, + EFFECT_MIND_BLOWN, + 0xFFFF +}; + // Functions +void RecordLastUsedMoveByTarget(void) +{ + RecordKnownMove(gBattlerTarget, gLastMoves[gBattlerTarget]); +} + +bool32 IsBattlerAIControlled(u32 battlerId) +{ + switch (GetBattlerPosition(battlerId)) + { + case B_POSITION_PLAYER_LEFT: + default: + return FALSE; + case B_POSITION_OPPONENT_LEFT: + return TRUE; + case B_POSITION_PLAYER_RIGHT: + return ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) != 0); + case B_POSITION_OPPONENT_RIGHT: + return TRUE; + } +} + +void ClearBattlerMoveHistory(u8 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(u8 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; + break; + } + } +} + +void RecordAbilityBattle(u8 battlerId, u16 abilityId) +{ + BATTLE_HISTORY->abilities[battlerId] = abilityId; +} + +void ClearBattlerAbilityHistory(u8 battlerId) +{ + BATTLE_HISTORY->abilities[battlerId] = ABILITY_NONE; +} + +void RecordItemEffectBattle(u8 battlerId, u8 itemEffect) +{ + BATTLE_HISTORY->itemEffects[battlerId] = itemEffect; +} + +void ClearBattlerItemEffectHistory(u8 battlerId) +{ + BATTLE_HISTORY->itemEffects[battlerId] = 0; +} + +void SaveBattlerData(u8 battlerId) +{ + if (!IsBattlerAIControlled(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]; + } +} + +void SetBattlerData(u8 battlerId) +{ + if (!IsBattlerAIControlled(battlerId)) + { + struct Pokemon *illusionMon; + u32 i; + + // Use the known battler's ability. + if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE) + gBattleMons[battlerId].ability = BATTLE_HISTORY->abilities[battlerId]; + // Check if mon can only have one ability. + else if (gBaseStats[gBattleMons[battlerId].species].abilities[1] == ABILITY_NONE + || gBaseStats[gBattleMons[battlerId].species].abilities[1] == gBaseStats[gBattleMons[battlerId].species].abilities[0]) + gBattleMons[battlerId].ability = gBaseStats[gBattleMons[battlerId].species].abilities[0]; + // The ability is unknown. + else + gBattleMons[battlerId].ability = ABILITY_NONE; + + if (BATTLE_HISTORY->itemEffects[battlerId] == 0) + gBattleMons[battlerId].item = 0; + + for (i = 0; i < 4; i++) + { + if (BATTLE_HISTORY->usedMoves[battlerId][i] == 0) + gBattleMons[battlerId].moves[i] = 0; + } + + // Simulate Illusion + if ((illusionMon = GetIllusionMonPtr(battlerId)) != NULL) + gBattleMons[battlerId].species = GetMonData(illusionMon, MON_DATA_SPECIES2); + } +} + +void RestoreBattlerData(u8 battlerId) +{ + if (!IsBattlerAIControlled(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]; + } +} + u32 GetHealthPercentage(u8 battlerId) { return (u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP); @@ -44,4 +194,295 @@ bool32 IsBattlerTrapped(u8 battler, bool8 switching) } return FALSE; -} \ No newline at end of file +} + +// Checks if one of the moves has side effects or perks +static u32 WhichMoveBetter(u32 move1, u32 move2) +{ + s32 defAbility = AI_GetAbility(gBattlerTarget, FALSE); + + // Check if physical moves hurt. + if (GetBattlerHoldEffect(sBattler_AI, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS + && (BATTLE_HISTORY->itemEffects[gBattlerTarget] == 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 recoil + if (GetBattlerAbility(sBattler_AI) != ABILITY_ROCK_HEAD) + { + if (((gBattleMoves[move1].effect == EFFECT_RECOIL_25 + || gBattleMoves[move1].effect == EFFECT_RECOIL_IF_MISS + || gBattleMoves[move1].effect == EFFECT_RECOIL_50 + || gBattleMoves[move1].effect == EFFECT_RECOIL_33 + || gBattleMoves[move1].effect == EFFECT_RECOIL_33_STATUS) + && (gBattleMoves[move2].effect != EFFECT_RECOIL_25 + && gBattleMoves[move2].effect != EFFECT_RECOIL_IF_MISS + && gBattleMoves[move2].effect != EFFECT_RECOIL_50 + && gBattleMoves[move2].effect != EFFECT_RECOIL_33 + && gBattleMoves[move2].effect != EFFECT_RECOIL_33_STATUS + && gBattleMoves[move2].effect != EFFECT_RECHARGE))) + return 1; + + if (((gBattleMoves[move2].effect == EFFECT_RECOIL_25 + || gBattleMoves[move2].effect == EFFECT_RECOIL_IF_MISS + || gBattleMoves[move2].effect == EFFECT_RECOIL_50 + || gBattleMoves[move2].effect == EFFECT_RECOIL_33 + || gBattleMoves[move2].effect == EFFECT_RECOIL_33_STATUS) + && (gBattleMoves[move1].effect != EFFECT_RECOIL_25 + && gBattleMoves[move1].effect != EFFECT_RECOIL_IF_MISS + && gBattleMoves[move1].effect != EFFECT_RECOIL_50 + && gBattleMoves[move1].effect != EFFECT_RECOIL_33 + && gBattleMoves[move1].effect != EFFECT_RECOIL_33_STATUS + && gBattleMoves[move1].effect != EFFECT_RECHARGE))) + return 0; + } + // Check recharge + if (gBattleMoves[move1].effect == EFFECT_RECHARGE && gBattleMoves[move2].effect != EFFECT_RECHARGE) + return 1; + if (gBattleMoves[move2].effect == EFFECT_RECHARGE && gBattleMoves[move1].effect != EFFECT_RECHARGE) + return 0; + // Check additional effect. + if (gBattleMoves[move1].effect == 0 && gBattleMoves[move2].effect != 0) + return 1; + if (gBattleMoves[move2].effect == 0 && gBattleMoves[move1].effect != 0) + return 0; + + return 2; +} + +u8 GetMovePowerResult(u16 move) +{ + s32 i, checkedMove, bestId, currId, hp; + s32 moveDmgs[MAX_MON_MOVES]; + u8 result; + + for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) + { + if (gBattleMoves[move].effect == sDiscouragedPowerfulMoveEffects[i]) + break; + } + + if (gBattleMoves[move].power != 0 && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF) + { + for (checkedMove = 0; checkedMove < MAX_MON_MOVES; checkedMove++) + { + for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) + { + if (gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].effect == sDiscouragedPowerfulMoveEffects[i]) + break; + } + + if (gBattleMons[sBattler_AI].moves[checkedMove] != MOVE_NONE + && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF + && gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].power != 0) + { + moveDmgs[checkedMove] = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][checkedMove]; + } + else + { + moveDmgs[checkedMove] = 0; + } + } + + hp = gBattleMons[gBattlerTarget].hp + (20 * gBattleMons[gBattlerTarget].hp / 100); // 20 % add to make sure the battler is always fainted + // If a move can faint battler, it doesn't matter how much damage it does + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moveDmgs[i] > hp) + moveDmgs[i] = hp; + } + + for (bestId = 0, i = 1; i < MAX_MON_MOVES; i++) + { + if (moveDmgs[i] > moveDmgs[bestId]) + bestId = i; + if (moveDmgs[i] == moveDmgs[bestId]) + { + switch (WhichMoveBetter(gBattleMons[sBattler_AI].moves[bestId], gBattleMons[sBattler_AI].moves[i])) + { + case 2: + if (Random() & 1) + break; + case 1: + bestId = i; + break; + } + } + } + + currId = AI_THINKING_STRUCT->movesetIndex; + if (currId == bestId) + AI_THINKING_STRUCT->funcResult = MOVE_POWER_BEST; + // Compare percentage difference. + else if ((moveDmgs[currId] >= hp || moveDmgs[bestId] < hp) // If current move can faint as well, or if neither can + && (moveDmgs[bestId] * 100 / hp) - (moveDmgs[currId] * 100 / hp) <= 30 + && WhichMoveBetter(gBattleMons[sBattler_AI].moves[bestId], gBattleMons[sBattler_AI].moves[currId]) != 0) + AI_THINKING_STRUCT->funcResult = MOVE_POWER_GOOD; + else + AI_THINKING_STRUCT->funcResult = MOVE_POWER_WEAK; + } + else + { + AI_THINKING_STRUCT->funcResult = MOVE_POWER_DISCOURAGED; // Highly discouraged in terms of power. + } + + return AI_THINKING_STRUCT->funcResult; +} + +u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) +{ + u16 typeEffectiveness, 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, FALSE); + + RestoreBattlerData(battlerAtk); + RestoreBattlerData(battlerDef); + + return typeEffectiveness; +} + +u8 GetMoveEffectiveness(u16 move) +{ + u8 damageVar; + u32 effectivenessMultiplier; + + gMoveResultFlags = 0; + gCurrentMove = move; + effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, sBattler_AI, gBattlerTarget); + switch (effectivenessMultiplier) + { + case UQ_4_12(0.0): + default: + damageVar = AI_EFFECTIVENESS_x0; + break; + case UQ_4_12(0.25): + damageVar = AI_EFFECTIVENESS_x0_25; + break; + case UQ_4_12(0.5): + damageVar = AI_EFFECTIVENESS_x0_5; + break; + case UQ_4_12(1.0): + damageVar = AI_EFFECTIVENESS_x1; + break; + case UQ_4_12(2.0): + damageVar = AI_EFFECTIVENESS_x2; + break; + case UQ_4_12(4.0): + damageVar = AI_EFFECTIVENESS_x4; + break; + } + + return damageVar; +} + +// 0: is user(ai) faster +// 1: is target faster +bool32 IsBattlerFaster(u8 battler) +{ + u32 fasterAI = 0, fasterPlayer = 0, i; + s8 prioAI, prioPlayer; + + // Check move priorities first. + prioAI = GetMovePriority(sBattler_AI, AI_THINKING_STRUCT->moveConsidered); + SaveBattlerData(gBattlerTarget); + SetBattlerData(gBattlerTarget); + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (gBattleMons[gBattlerTarget].moves[i] == 0 || gBattleMons[gBattlerTarget].moves[i] == 0xFFFF) + continue; + + prioPlayer = GetMovePriority(gBattlerTarget, gBattleMons[gBattlerTarget].moves[i]); + if (prioAI > prioPlayer) + fasterAI++; + else if (prioPlayer > prioAI) + fasterPlayer++; + } + RestoreBattlerData(gBattlerTarget); + + if (fasterAI > fasterPlayer) + { + if (battler == 0) // is user (ai) faster + return TRUE; + else + return FALSE; + } + else if (fasterAI < fasterPlayer) + { + if (battler == 1) // is target (player) faster + return TRUE; + else + return FALSE; + } + else + { + // Priorities are the same(at least comparing to moves the AI is aware of), decide by speed. + if (GetWhoStrikesFirst(sBattler_AI, gBattlerTarget, TRUE) == battler) + return TRUE; + else + return FALSE; + } +} + +// Check if target has means to faint ai mon. +bool32 CanTargetFaintAi(void) +{ + s32 i, dmg; + u32 unusable = CheckMoveLimitations(gBattlerTarget, 0, 0xFF & ~MOVE_LIMITATION_PP); + u16 *moves = gBattleResources->battleHistory->usedMoves[gBattlerTarget]; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i]) + && AI_CalcDamage(moves[i], gBattlerTarget, sBattler_AI) >= gBattleMons[sBattler_AI].hp) + { + return TRUE; + } + } + + return FALSE; +} + +s32 AI_GetAbility(u32 battlerId, bool32 guess) +{ + // The AI knows its own ability. + if (IsBattlerAIControlled(battlerId)) + return gBattleMons[battlerId].ability; + + if (BATTLE_HISTORY->abilities[battlerId] != 0) + return BATTLE_HISTORY->abilities[battlerId]; + + // Abilities that prevent fleeing. + if (gBattleMons[battlerId].ability == ABILITY_SHADOW_TAG + || gBattleMons[battlerId].ability == ABILITY_MAGNET_PULL + || gBattleMons[battlerId].ability == ABILITY_ARENA_TRAP) + return gBattleMons[battlerId].ability; + + if (gBaseStats[gBattleMons[battlerId].species].abilities[0] != ABILITY_NONE) + { + if (gBaseStats[gBattleMons[battlerId].species].abilities[1] != ABILITY_NONE) + { + // AI has no knowledge of opponent, so it guesses which ability. + if (guess) + return gBaseStats[gBattleMons[battlerId].species].abilities[Random() & 1]; + } + else + { + return gBaseStats[gBattleMons[battlerId].species].abilities[0]; // It's definitely ability 1. + } + } + return -1; // Unknown. +} + From ac332d5e98d542a112d91394f9e7ac588d54608d Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 13 Dec 2020 15:02:21 -0700 Subject: [PATCH 04/36] check bad move --- data/battle_ai_scripts.s | 32 +- include/battle_ai_util.h | 72 +- include/battle_script_commands.h | 9 + include/battle_util.h | 14 + include/constants/battle.h | 2 + include/constants/battle_ai.h | 34 +- include/constants/battle_config.h | 1 + include/constants/hold_effects.h | 8 + src/battle_ai_script_commands.c | 2155 +++++++++++++++++++++++++++-- src/battle_ai_util.c | 1126 ++++++++++++++- src/battle_factory.c | 6 +- src/battle_script_commands.c | 163 +-- src/battle_util.c | 254 +++- src/data/trainers.h | 1678 +++++++++++----------- src/trainer_hill.c | 2 +- 15 files changed, 4408 insertions(+), 1148 deletions(-) diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index 9e504dd55e..c71c6b3c1b 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -22,6 +22,7 @@ gBattleAI_ScriptsTable:: @ 82DBEF8 .4byte AI_DoubleBattle @ AI_SCRIPT_DOUBLE_BATTLE .4byte AI_HPAware @ AI_SCRIPT_HP_AWARE +AI_TryToFaint: AI_CheckBadMove: if_target_is_ally AI_Ret @@ -3402,36 +3403,7 @@ AI_CV_DragonDance2: AI_CV_DragonDance_End: end -AI_TryToFaint: - if_target_is_ally AI_Ret - if_can_faint AI_TryToFaint_Can - get_how_powerful_move_is - if_equal MOVE_POWER_DISCOURAGED, Score_Minus1 -AI_TryToFaint2: - if_type_effectiveness AI_EFFECTIVENESS_x4, AI_TryToFaint_DoubleSuperEffective - goto AI_TryToFaint_CheckIfDanger -AI_TryToFaint_DoubleSuperEffective: - if_random_less_than 80, AI_TryToFaint_CheckIfDanger - score +2 - goto AI_TryToFaint_CheckIfDanger -AI_TryToFaint_Can: - if_effect EFFECT_EXPLOSION, AI_TryToFaint_CheckIfDanger - if_user_faster AI_TryToFaint_ScoreUp4 - if_move_flag FLAG_HIGH_CRIT, AI_TryToFaint_ScoreUp4 - score +2 - goto AI_TryToFaint_CheckIfDanger -AI_TryToFaint_ScoreUp4: - score +4 -AI_TryToFaint_CheckIfDanger: - if_user_faster AI_TryToFaint_End - if_ai_can_go_down AI_TryToFaint_Danger -AI_TryToFaint_End: - end -AI_TryToFaint_Danger: - get_how_powerful_move_is - if_not_equal MOVE_POWER_BEST, Score_Minus1 - score +1 - goto AI_TryToFaint_End + AI_SetupFirstTurn: if_target_is_ally AI_Ret diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index dd9fe2a8a1..5d778ef3fd 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -5,6 +5,8 @@ #define AI_CHECK_FASTER 0 // if_user_faster #define AI_CHECK_SLOWER 1 // if_target_faster +#define FOE(battler) ((battler ^ BIT_SIDE) & BIT_SIDE) + void RecordLastUsedMoveByTarget(void); bool32 IsBattlerAIControlled(u32 battlerId); void ClearBattlerMoveHistory(u8 battlerId); @@ -20,11 +22,73 @@ void RestoreBattlerData(u8 battlerId); u32 GetHealthPercentage(u8 battler); bool32 IsBattlerTrapped(u8 battler, bool8 switching); +bool32 IsBattlerFaster(u8 battler); +bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk); +s32 AI_GetAbility(u32 battlerId); +u16 AI_GetHoldEffect(u32 battlerId); +u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move); +bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move); +bool32 AI_WeatherHasEffect(void); +bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index); +s32 CountUsablePartyMons(u8 battlerId); +bool32 IsPartyFullyHealedExceptBattler(u8 battler); +bool32 AI_IsBattlerGrounded(u8 battlerId); +bool32 BattlerHasDamagingMove(u8 battlerId); +bool32 BattlerHasSecondaryDamage(u8 battlerId); +bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability); +bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move); +bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex); +u16 GetBattlerSideSpeedAverage(u8 battler); + +// stat stage checks +bool32 AnyStatIsRaised(u8 battlerId); +bool32 BattlerStatCanFall(u8 battler, u16 battlerAbility, u8 stat); +bool32 BattlerStatCanRise(u8 battler, u16 battlerAbility, u8 stat); +bool32 AreBattlersStatsMaxed(u8 battler); +bool32 BattlerHasAnyStatRaised(u8 battlerId); +u32 CountPositiveStatStages(u8 battlerId); +u32 CountNegativeStatStages(u8 battlerId); +bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability); + +// move checks u8 GetMovePowerResult(u16 move); u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); -u8 GetMoveEffectiveness(u16 move); -bool32 IsBattlerFaster(u8 battler); -bool32 CanTargetFaintAi(void); -s32 AI_GetAbility(u32 battlerId, bool32 guess); +u8 AI_GetMoveEffectiveness(u16 move); +u16 *GetMovesArray(u32 battler); +bool32 IsConfusionMoveEffect(u16 moveEffect); +bool32 HasMoveWithSplit(u32 battler, u32 split); +bool32 HasMoveWithType(u32 battler, u8 type); +bool32 TestMoveFlagsInMoveset(u8 battler, u32 flags); +bool32 IsAromaVeilProtectedMove(u16 move); +bool32 IsNonVolatileStatusMoveEffect(u16 moveEffect); +bool32 IsStatLoweringMoveEffect(u16 moveEffect); +bool32 IsMoveRedirectionPrevented(u16 move, u16 atkAbility); +bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move); +bool32 IsHazardMoveEffect(u16 moveEffect); +bool32 MoveCallsOtherMove(u16 move); +bool32 MoveRequiresRecharging(u16 move); +bool32 IsInstructBannedMove(u16 move); + +// status checks +bool32 AI_ShouldPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); +bool32 AI_ShouldPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); +bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); +bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof); +bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); +bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); +bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGender, u8 defGender); + +// partner logic +u16 GetAllyChosenMove(void); +bool32 IsValidDoubleBattle(u8 battlerAtk); +bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef); +bool32 DoesPartnerHaveSameMoveEffect(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove); +bool32 PartnerHasSameMoveEffectWithoutTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove); +bool32 PartnerMoveEffectIsStatusSameTarget(u8 battlerAtkPartner, u8 battlerDef, u16 partnerMove); +bool32 PartnerMoveEffectIsWeather(u8 battlerAtkPartner, u16 partnerMove); +bool32 PartnerMoveEffectIsTerrain(u8 battlerAtkPartner, u16 partnerMove); +bool32 PartnerMoveIs(u8 battlerAtkPartner, u16 partnerMove, u16 moveCheck); +bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove); +bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove); #endif //GUARD_BATTLE_AI_UTIL_H \ No newline at end of file diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 454b6ab345..693fdb36f5 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -6,6 +6,12 @@ #define WINDOW_CLEAR 0x1 #define WINDOW_x80 0x80 +struct StatFractions +{ + u8 dividend; + u8 divisor; +}; + s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility); u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move); u8 GetBattlerTurnOrderNum(u8 battlerId); @@ -26,8 +32,11 @@ u32 IsFlowerVeilProtected(u32 battler); u32 IsLeafGuardProtected(u32 battler); bool32 IsShieldsDownProtected(u32 battler); u32 IsAbilityStatusProtected(u32 battler); +bool32 CanCamouflage(u8 battlerId); +u16 GetNaturePowerMove(void); extern void (* const gBattleScriptingCommandsTable[])(void); extern const u8 gBattlePalaceNatureToMoveGroupLikelihood[NUM_NATURES][4]; +extern const struct StatFractions gAccuracyStageRatios[]; #endif // GUARD_BATTLE_SCRIPT_COMMANDS_H diff --git a/include/battle_util.h b/include/battle_util.h index f7699fceda..b26ea09398 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -130,5 +130,19 @@ void ClearIllusionMon(u32 battlerId); bool32 SetIllusionMon(struct Pokemon *mon, u32 battlerId); bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battlerId); u8 GetBattleMoveSplit(u32 moveId); +bool32 TestMoveFlags(u16 move, u32 flag); +struct Pokemon *GetBattlerPartyData(u8 battlerId); +bool32 CanFling(u8 battlerId); +bool32 IsTelekinesisBannedSpecies(u16 species); +bool32 IsHealBlockPreventingMove(u32 battler, u32 move); + +// ability checks +bool32 IsRolePlayBannedAbilityAtk(u16 ability); +bool32 IsRolePlayBannedAbility(u16 ability); +bool32 IsSkillSwapBannedAbility(u16 ability); +bool32 IsWorrySeedBannedAbility(u16 ability); +bool32 IsGastroAcidBannedAbility(u16 ability); +bool32 IsEntrainmentBannedAbilityAttacker(u16 ability); +bool32 IsEntrainmentTargetOrSimpleBeamBannedAbility(u16 ability); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/constants/battle.h b/include/constants/battle.h index 40c604c9ed..0bc06b0adb 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -220,6 +220,8 @@ #define SIDE_STATUS_CRAFTY_SHIELD (1 << 20) #define SIDE_STATUS_MAT_BLOCK (1 << 21) +#define SIDE_HAZARDS_ANY (SIDE_STATUS_SPIKES | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_STEALTH_ROCK) + // Field affecting statuses. #define STATUS_FIELD_MAGIC_ROOM 0x1 #define STATUS_FIELD_TRICK_ROOM 0x2 diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 974ef2b770..dd29f20f2e 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -35,20 +35,24 @@ #define MOVE_POWER_GOOD 2 // Similar dmg range with best. #define MOVE_POWER_WEAK 3 // Significantly lower than best and good. -// script's table id to bit -#define AI_SCRIPT_CHECK_BAD_MOVE (1 << 0) -#define AI_SCRIPT_TRY_TO_FAINT (1 << 1) -#define AI_SCRIPT_CHECK_VIABILITY (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) +// 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) +#define AI_FLAG_HP_AWARE (1 << 8) +// Flags that don't run specific checks themselves, but are used in other score functions +#define AI_FLAG_NEGATE_AWARE (1 << 9) // AI is aware of negating effects like wonder room, mold breaker, etc (eg. smart trainers). TODO unfinished +#define AI_FLAG_HELP_PARTNER (1 << 10) // AI can try to help partner. If not set, will tend not to target partner +#define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc + +// 'other' ai logic flags +#define AI_FLAG_ROAMING (1 << 29) +#define AI_FLAG_SAFARI (1 << 30) +#define AI_FLAG_FIRST_BATTLE (1 << 31) #endif // GUARD_CONSTANTS_BATTLE_AI_H diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 55c62af987..9abe4c82d4 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -123,6 +123,7 @@ // Item settings #define B_HP_BERRIES GEN_6 // In Gen4+, berries which restore hp activate immediately after hp drops to half. In gen3, the effect occurs at the end of the turn. #define B_BERRIES_INSTANT GEN_6 // In Gen4+, most berries activate on battle start/switch-in if applicable. In gen3, they only activate either at the move end or turn end. +#define B_MENTAL_HERB GEN_5 // In Gen5+, mental herb cures Taunt, Encore, Heal Block, and Disable // Flag settings. // To use the following features in scripting, replace the 0s with the flag ID you're assigning it to. Eg: Replace with FLAG_UNUSED_0x264 so you can use that flag for toggling the feature. diff --git a/include/constants/hold_effects.h b/include/constants/hold_effects.h index 85017cb405..bf983cf5e6 100644 --- a/include/constants/hold_effects.h +++ b/include/constants/hold_effects.h @@ -136,6 +136,14 @@ #define HOLD_EFFECT_MEMORY 153 #define HOLD_EFFECT_PLATE 154 +// Gen8 hold effects +#define HOLD_EFFECT_UTILITY_UMBRELLA 155 +#define HOLD_EFFECT_EJECT_PACK 156 +#define HOLD_EFFECT_ROOM_SERVICE 157 +#define HOLD_EFFECT_BLUNDER_POLICY 158 +#define HOLD_EFFECT_HEAVY_DUTY_BOOTS 159 +#define HOLD_EFFECT_THROAT_SPRAY 160 + #define HOLD_EFFECT_CHOICE(holdEffect)((holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF || holdEffect == HOLD_EFFECT_CHOICE_SPECS)) #endif // GUARD_HOLD_EFFECTS_H diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 1e0b414d07..5144e5ce88 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -27,6 +27,18 @@ #define AI_ACTION_UNK7 0x0040 #define AI_ACTION_UNK8 0x0080 +#define RETURN_SCORE_MINUS(a) \ +{ \ + score -= a; \ + return score; \ +} +#define RETURN_SCORE_PLUS(a) \ +{ \ + score += a; \ + return score; \ +} + + // AI states enum { @@ -51,7 +63,6 @@ static u8 ChooseMoveOrAction_Doubles(void); static void BattleAI_DoAIProcessing(void); static void AIStackPushVar(const u8 *); static bool8 AIStackPop(void); -static s32 CountUsablePartyMons(u8 battlerId); static void Cmd_if_random_less_than(void); static void Cmd_if_random_greater_than(void); @@ -198,16 +209,16 @@ static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 orig static u8 (*const sBattleAiFuncTable[])(u8, u8, u16, u8) = { - [0] = AI_CheckBadMove, // AI_SCRIPT_CHECK_BAD_MOVE - [1] = AI_TryToFaint, // AI_SCRIPT_TRY_TO_FAINT - [2] = AI_CheckViability, // AI_SCRIPT_CHECK_VIABILITY - [3] = AI_SetupFirstTurn, // AI_SCRIPT_SETUP_FIRST_TURN - [4] = AI_Risky, // AI_SCRIPT_RISKY - [5] = AI_PreferStrongestMove, // AI_SCRIPT_PREFER_STRONGEST_MOVE - [6] = AI_PreferBatonPass, // AI_SCRIPT_PREFER_BATON_PASS - [7] = AI_DoubleBattle, // AI_SCRIPT_DOUBLE_BATTLE - [8] = AI_HPAware, // AI_SCRIPT_HP_AWARE - [9] = NULL, // Unused + [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] = NULL, // Unused [10] = NULL, // Unused [11] = NULL, // Unused [12] = NULL, // Unused @@ -227,9 +238,9 @@ static u8 (*const sBattleAiFuncTable[])(u8, u8, u16, u8) = [26] = NULL, // Unused [27] = NULL, // Unused [28] = NULL, // Unused - [29] = AI_Roaming, // AI_SCRIPT_ROAMING - [30] = AI_Safari, // AI_SCRIPT_SAFARI - [31] = AI_FirstBattle, // AI_SCRIPT_FIRST_BATTLE + [29] = AI_Roaming, // AI_FLAG_ROAMING + [30] = AI_Safari, // AI_FLAG_SAFARI + [31] = AI_FirstBattle, // AI_FLAG_FIRST_BATTLE }; static const BattleAICmdFunc sBattleAICmdTable[] = @@ -391,22 +402,22 @@ void BattleAI_SetupFlags(void) if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) AI_THINKING_STRUCT->aiFlags = GetAiScriptsInRecordedBattle(); else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) - AI_THINKING_STRUCT->aiFlags = AI_SCRIPT_SAFARI; + AI_THINKING_STRUCT->aiFlags = AI_FLAG_SAFARI; else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) - AI_THINKING_STRUCT->aiFlags = AI_SCRIPT_ROAMING; + AI_THINKING_STRUCT->aiFlags = AI_FLAG_ROAMING; else if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) - AI_THINKING_STRUCT->aiFlags = AI_SCRIPT_FIRST_BATTLE; + AI_THINKING_STRUCT->aiFlags = AI_FLAG_FIRST_BATTLE; else if (gBattleTypeFlags & BATTLE_TYPE_FACTORY) AI_THINKING_STRUCT->aiFlags = GetAiScriptsInBattleFactory(); else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE)) - AI_THINKING_STRUCT->aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_TRY_TO_FAINT; + AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT; else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags | gTrainers[gTrainerBattleOpponent_B].aiFlags; else AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags; if (gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS) || gTrainers[gTrainerBattleOpponent_A].doubleBattle) - AI_THINKING_STRUCT->aiFlags |= AI_SCRIPT_DOUBLE_BATTLE; // Act smart in doubles and don't attack your partner. + AI_THINKING_STRUCT->aiFlags |= AI_FLAG_DOUBLE_BATTLE; // Act smart in doubles and don't attack your partner. } void BattleAI_SetupAIData(u8 defaultScoreMoves) @@ -542,13 +553,13 @@ static u8 ChooseMoveOrAction_Singles(void) && !(gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) && !(gStatuses3[gActiveBattler] & STATUS3_ROOTED) && !(gBattleTypeFlags & (BATTLE_TYPE_ARENA | BATTLE_TYPE_PALACE)) - && AI_THINKING_STRUCT->aiFlags & (AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_PREFER_BATON_PASS)) + && AI_THINKING_STRUCT->aiFlags & (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[sBattler_AI].species) >= 310 // Mon is not weak. && gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2) { - s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_SCRIPT_CHECK_VIABILITY) ? 95 : 93; + s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY) ? 95 : 93; for (i = 0; i < MAX_MON_MOVES; i++) { if (AI_THINKING_STRUCT->score[i] > cap) @@ -1220,19 +1231,7 @@ static void Cmd_if_user_has_attacking_move(void) static void Cmd_if_user_has_no_attacking_moves(void) { - s32 i; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[sBattler_AI].moves[i] != 0 - && gBattleMoves[gBattleMons[sBattler_AI].moves[i]].power != 0) - break; - } - - if (i != MAX_MON_MOVES) - gAIScriptPtr += 5; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); + //BattlerHasDamagingMove } static void Cmd_get_turn_count(void) @@ -1326,42 +1325,6 @@ static void Cmd_nullsub_2B(void) { } -static s32 CountUsablePartyMons(u8 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(GetBattlerPosition(battlerId) ^ BIT_FLANK)]; - } - 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_SPECIES2) != SPECIES_NONE - && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG) - { - ret++; - } - } - - return ret; -} - static void Cmd_count_usable_party_mons(void) { AI_THINKING_STRUCT->funcResult = CountUsablePartyMons(BattleAI_GetWantedBattler(gAIScriptPtr[1])); @@ -1382,13 +1345,13 @@ static void Cmd_get_considered_move_effect(void) static void Cmd_get_ability(void) { - AI_THINKING_STRUCT->funcResult = AI_GetAbility(BattleAI_GetWantedBattler(gAIScriptPtr[1]), TRUE); + //AI_THINKING_STRUCT->funcResult = AI_GetAbility(BattleAI_GetWantedBattler(gAIScriptPtr[1]), TRUE); gAIScriptPtr += 2; } static void Cmd_check_ability(void) { - u32 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); + /*u32 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); u32 ability = AI_GetAbility(battlerId, FALSE); if (ability == -1) @@ -1398,7 +1361,7 @@ static void Cmd_check_ability(void) else AI_THINKING_STRUCT->funcResult = 0; // Pokemon doesn't have the ability we wanted to check. - gAIScriptPtr += 3; + gAIScriptPtr += 3;*/ } static void Cmd_get_highest_type_effectiveness(void) @@ -1447,7 +1410,7 @@ static void Cmd_get_highest_type_effectiveness(void) static void Cmd_if_type_effectiveness(void) { - // GetMoveEffectiveness + // AI_GetMoveEffectiveness } static void Cmd_nullsub_32(void) @@ -1863,14 +1826,7 @@ static void Cmd_watch(void) static void Cmd_get_hold_effect(void) { - u32 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if (!IsBattlerAIControlled(battlerId)) - AI_THINKING_STRUCT->funcResult = BATTLE_HISTORY->itemEffects[battlerId]; - else - AI_THINKING_STRUCT->funcResult = GetBattlerHoldEffect(battlerId, FALSE); - - gAIScriptPtr += 2; + // AI_GetHoldEffect } static void Cmd_if_holds_item(void) @@ -2148,15 +2104,7 @@ static bool8 AIStackPop(void) static void Cmd_get_ally_chosen_move(void) { - u8 partnerBattler = BATTLE_PARTNER(sBattler_AI); - if (!IsBattlerAlive(partnerBattler) || !IsBattlerAIControlled(partnerBattler)) - AI_THINKING_STRUCT->funcResult = 0; - else if (partnerBattler > sBattler_AI) // Battler with the lower id chooses the move first. - AI_THINKING_STRUCT->funcResult = 0; - else - AI_THINKING_STRUCT->funcResult = gBattleMons[partnerBattler].moves[gBattleStruct->chosenMovePositions[partnerBattler]]; - - gAIScriptPtr++; + // GetAllyChosenMove } static void Cmd_if_has_no_attacking_moves(void) @@ -2241,28 +2189,6 @@ static void Cmd_if_cant_use_last_resort(void) gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); } -static u16 *GetMovesArray(u32 battler) -{ - if (IsBattlerAIControlled(battler) || IsBattlerAIControlled(BATTLE_PARTNER(battler))) - return gBattleMons[battler].moves; - else - return gBattleResources->battleHistory->usedMoves[battler]; -} - -static bool32 HasMoveWithSplit(u32 battler, u32 split) -{ - s32 i; - u16 *moves = GetMovesArray(battler); - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && GetBattleMoveSplit(moves[i]) == split) - return TRUE; - } - - return FALSE; -} - static void Cmd_if_has_move_with_split(void) { if (HasMoveWithSplit(BattleAI_GetWantedBattler(gAIScriptPtr[1]), gAIScriptPtr[2])) @@ -2508,30 +2434,1994 @@ static void Cmd_if_has_move_with_accuracy_lt(void) - - // AI Functions static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) -{ +{ + // attacker data + u16 atkAbility = AI_GetAbility(battlerAtk); + u8 atkHoldEffect = AI_GetHoldEffect(battlerAtk); + u8 atkParam = GetBattlerHoldEffectParam(battlerAtk); + u8 atkPriority = GetMovePriority(battlerAtk, move); + // target data + u16 defAbility = AI_GetAbility(battlerDef); + u8 defHoldEffect = AI_GetHoldEffect(battlerDef); + u8 defParam = GetBattlerHoldEffectParam(battlerDef); + // attacker partner data + u8 battlerAtkPartner = BATTLE_PARTNER(battlerAtk); + u16 partnerMove = GetAllyChosenMove(); + u16 atkPartnerAbility = AI_GetAbility(battlerAtkPartner); + bool32 targetSameSide = IsTargetingPartner(battlerAtk, battlerDef); + // target partner data + u8 battlerDefPartner = BATTLE_PARTNER(battlerDef); + u16 defPartnerAbility = AI_GetAbility(battlerDefPartner); + // move data + s16 score = originalScore; + u16 moveEffect = gBattleMoves[move].effect; + u8 moveType = gBattleMoves[move].type; + u8 moveTarget = gBattleMoves[move].target; + u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, move); + u8 effectiveness = AI_GetMoveEffectiveness(move); + + if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HELP_PARTNER) && targetSameSide) + return originalScore; // don't consider ally presence + + if (!(gBattleMoves[move].target & MOVE_TARGET_USER)) + { + // handle negative checks on non-user target + // check powder moves + if (TestMoveFlags(move, FLAG_POWDER)) + { + if ((B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS)) + || defAbility == ABILITY_OVERCOAT + || GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_SAFETY_GOOGLES) + RETURN_SCORE_MINUS(10); + } + + // check ground immunities + if (moveType == TYPE_GROUND + && !IsBattlerGrounded(battlerDef) + && ((defAbility == ABILITY_LEVITATE + && DoesBattlerIgnoreAbilityChecks(atkAbility, move)) + || defHoldEffect == HOLD_EFFECT_AIR_BALLOON + || (gStatuses3[battlerDef] & (STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS))) + && move != MOVE_THOUSAND_ARROWS) + { + RETURN_SCORE_MINUS(10); + } + + // check if negates type + if (effectiveness == AI_EFFECTIVENESS_x0) + RETURN_SCORE_MINUS(20); + + // target ability checks + if (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) + { + switch (defAbility) + { + case ABILITY_VOLT_ABSORB: + case ABILITY_MOTOR_DRIVE: + case ABILITY_LIGHTNING_ROD: + if (moveType == TYPE_ELECTRIC && !IsTargetingPartner(battlerAtk, battlerDef)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_WATER_ABSORB: + case ABILITY_DRY_SKIN: + case ABILITY_STORM_DRAIN: + if (moveType == TYPE_WATER && !IsTargetingPartner(battlerAtk, battlerDef)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_FLASH_FIRE: + if (moveType == TYPE_FIRE && !IsTargetingPartner(battlerAtk, battlerDef)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_WONDER_GUARD: + if (effectiveness != AI_EFFECTIVENESS_x2 && effectiveness != AI_EFFECTIVENESS_x4) + return 0; + break; + case ABILITY_SAP_SIPPER: + if (moveType == TYPE_GRASS && !IsTargetingPartner(battlerAtk, battlerDef)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_JUSTIFIED: + if (moveType == TYPE_DARK && !IS_MOVE_STATUS(move) && !IsTargetingPartner(battlerAtk, battlerDef)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_RATTLED: + if (!IS_MOVE_STATUS(move) + && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) + && !IsTargetingPartner(battlerAtk, battlerDef)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_SOUNDPROOF: + if (TestMoveFlags(move, FLAG_SOUND)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_BULLETPROOF: + if (TestMoveFlags(move, FLAG_BALLISTIC)) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_DAZZLING: + case ABILITY_QUEENLY_MAJESTY: + 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) || IsStatLoweringMoveEffect(moveEffect))) + RETURN_SCORE_MINUS(10); + break; + case ABILITY_MAGIC_BOUNCE: + if (TestMoveFlags(move, FLAG_MAGICCOAT_AFFECTED)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_CONTRARY: + if (IsStatLoweringMoveEffect(moveEffect) && !IsTargetingPartner(battlerAtk, battlerDef)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_CLEAR_BODY: + //case ABILITY_FULL_METAL_BODY: // maybe? + case ABILITY_WHITE_SMOKE: + if (IsStatLoweringMoveEffect(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_KEEN_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 (IsStatLoweringMoveEffect(moveEffect) && !IsTargetingPartner(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_WONDER_SKIN: + if (IS_MOVE_STATUS(move)) + accuracy = 50; + break; + case ABILITY_LEAF_GUARD: + if (AI_WeatherHasEffect() && (gBattleWeather & WEATHER_SUN_ANY) + && defHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA + && IsNonVolatileStatusMoveEffect(moveEffect)) + RETURN_SCORE_MINUS(10); + break; + } // def ability checks + + // target partner ability checks + if (IsValidDoubleBattle(battlerAtk) && !IsTargetingPartner(battlerAtk, battlerDef)) + { + switch (defPartnerAbility) + { + case ABILITY_LIGHTNING_ROD: + if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(move, atkAbility)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_STORM_DRAIN: + if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(move, atkAbility)) + RETURN_SCORE_MINUS(20); + break; + case ABILITY_MAGIC_BOUNCE: + if (TestMoveFlags(move, FLAG_MAGICCOAT_AFFECTED) && 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(10); + break; + case ABILITY_FLOWER_VEIL: + if ((IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS)) && (IsNonVolatileStatusMoveEffect(moveEffect) || IsStatLoweringMoveEffect(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: + if (atkPriority > 0) + RETURN_SCORE_MINUS(10); + break; + } + } // def partner ability checks + } // ignore def ability check + + #if B_PRANKSTER < GEN_7 + if (atkAbility == ABILITY_PRANKSTER && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) && IS_MOVE_STATUS(move) + && !(moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER))) + RETURN_SCORE_MINUS(10); + #endif + + // terrain effect checks + if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + { + if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) + RETURN_SCORE_MINUS(10); + } + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + { + if (IsNonVolatileStatusMoveEffect(moveEffect) || IsConfusionMoveEffect(moveEffect)) + RETURN_SCORE_MINUS(10); + } + if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + { + if (atkPriority > 0) + RETURN_SCORE_MINUS(10); + } + } // end check MOVE_TARGET_USER +// the following checks apply to any target (including user) + + // throat chop check + if (gDisableStructs[battlerAtk].throatChopTimer && TestMoveFlags(move, FLAG_SOUND)) + 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 + //TODO + + // check move effects + switch (moveEffect) + { + case EFFECT_HIT: + default: + break; + case EFFECT_SLEEP: + if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + score -= 10; + else if (!AI_ShouldPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + break; + case EFFECT_ABSORB: + if (defAbility == ABILITY_LIQUID_OOZE) + score -= 6; + break; + case EFFECT_STRENGTH_SAP: + if (defAbility == ABILITY_CONTRARY) + score -= 10; + else if (!BattlerStatCanFall(battlerDef, defAbility, STAT_ATK)) + score -= 10; + break; + case EFFECT_EXPLOSION: + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE) + { + if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(atkAbility, move)) + { + score -= 10; + } + else if (CountUsablePartyMons(battlerDef) == 1 && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex)) + { + ; // target has 1 pkmn left but you can faint it -> good to use + } + else if (IsValidDoubleBattle(battlerAtk)) + { + if (CountUsablePartyMons(battlerDef) == 2 + && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) + && CanAttackerFaintTarget(battlerAtkPartner, BATTLE_PARTNER(battlerDef), *(gBattleStruct->chosenMovePositions + battlerAtkPartner))) + { + ; // good + } + else + { + score -= 4; + } + } + else + { + if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex)) + { + if (CountUsablePartyMons(battlerDef) == 1) + { + ; //Good to use move + } + } + else + { + score -= 4; + } + } + } + else + { + score -= 4; + } + break; + case EFFECT_DREAM_EATER: + if (defAbility != ABILITY_COMATOSE && !(gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) + score -= 10; + break; + case EFFECT_COPYCAT: + //TODO - predict def move + break; + case EFFECT_MIRROR_MOVE: + //TODO - predict def move + break; + case EFFECT_TELEPORT: + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + if (CountUsablePartyMons(battlerAtk) == 1) + score -= 10; + } + else if (GetBattlerSide(battlerAtk) == B_SIDE_OPPONENT) + { + if (IsValidDoubleBattle(battlerAtk) || IsBattlerTrapped(battlerAtk, FALSE)) + score -= 10; + } + break; + case EFFECT_ATTACK_UP: + case EFFECT_ATTACK_UP_2: + if (atkAbility != ABILITY_CONTRARY) + { + if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + score -= 10; + } + else + { + score -= 10; + } + break; + case EFFECT_ATTACK_ACCURACY_UP: //hone claws + if (atkAbility != ABILITY_CONTRARY) + { + if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE + && (gBattleMons[battlerAtk].statStages[STAT_ACC] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL))) + score -= 10; + break; + } + else + { + score -= 10; + } + break; + case EFFECT_DEFENSE_UP: + case EFFECT_DEFENSE_UP_2: + case EFFECT_DEFENSE_CURL: + if (move == MOVE_STUFF_CHEEKS) + { + if (ItemId_GetPocket(gBattleMons[battlerAtk].item) != POCKET_BERRIES) // AI knows its own item + score -= 10; + } + else + { + if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_DEF)) + score -= 10; + } + break; + case EFFECT_FLOWER_SHIELD: + if (!IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) + && !(IsValidDoubleBattle(battlerAtk) && IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_GRASS))) + score -= 10; + break; + case EFFECT_MAGNETIC_FLUX: + if (atkAbility == ABILITY_PLUS || atkAbility == ABILITY_MINUS) + { + if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE + && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) + score -= 10; + } + else if (!IsValidDoubleBattle(battlerAtk)) + { + score -= 10; // our stats wont rise from this move + } + + if (IsValidDoubleBattle(battlerAtk)) + { + if (atkPartnerAbility == ABILITY_PLUS || atkPartnerAbility == ABILITY_MINUS) + { + if ((gBattleMons[battlerAtkPartner].statStages[STAT_DEF] >= MAX_STAT_STAGE) + && (gBattleMons[battlerAtkPartner].statStages[STAT_SPDEF] >= MAX_STAT_STAGE)) + score -= 10; + } + else if (atkAbility != ABILITY_PLUS && atkAbility != ABILITY_MINUS) + { + score -= 10; // nor our or our partner's ability is plus/minus + } + } + break; + case EFFECT_AROMATIC_MIST: + if (!IsValidDoubleBattle(battlerAtk) || gBattleMons[battlerAtkPartner].hp == 0 || !BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPDEF)) + score -= 10; + break; + case EFFECT_SPEED_UP: + case EFFECT_SPEED_UP_2: + if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPEED)) + score -= 10; + break; + case EFFECT_SPECIAL_ATTACK_UP: + case EFFECT_SPECIAL_ATTACK_UP_2: + if (atkAbility == ABILITY_CONTRARY + || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPATK) + || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + score -= 10; + break; + case EFFECT_GROWTH: + case EFFECT_ATTACK_SPATK_UP: // work up + if (!BattlerShouldRaiseAttacks(battlerAtk, atkAbility)) + score -= 10; + break; + case EFFECT_ROTOTILLER: + if (IsValidDoubleBattle(battlerAtk)) + { + if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) + && AI_IsBattlerGrounded(battlerAtk) + && atkAbility != ABILITY_CONTRARY + && (BattlerStatCanRise(battlerAtk, atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPATK))) + && !(IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_GRASS) + && AI_IsBattlerGrounded(battlerAtkPartner) + && atkPartnerAbility != ABILITY_CONTRARY + && (BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) + || BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)))) + { + score -= 10; + } + } + else if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) + && AI_IsBattlerGrounded(battlerAtk) + && atkAbility != ABILITY_CONTRARY + && (BattlerStatCanRise(battlerAtk, atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPATK)))) + { + score -= 10; + } + break; + case EFFECT_GEAR_UP: + if (atkAbility == ABILITY_PLUS || atkAbility == ABILITY_MINUS) + { + if (!BattlerShouldRaiseAttacks(battlerAtk, atkAbility)) + score -= 10; + } + else if (!IsValidDoubleBattle(battlerAtk)) + { + score -= 10; // no partner and our stats wont rise, so don't use + } + + if (IsValidDoubleBattle(battlerAtk)) + { + if (atkPartnerAbility == ABILITY_PLUS || atkPartnerAbility == ABILITY_MINUS) + { + if ((!BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + && (!BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL))) + score -= 10; + } + else if (atkAbility != ABILITY_PLUS && atkAbility != ABILITY_MINUS) + { + score -= 10; // nor our or our partner's ability is plus/minus + } + } + break; + case EFFECT_SPECIAL_DEFENSE_UP: + case EFFECT_SPECIAL_DEFENSE_UP_2: + if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPDEF)) + score -= 10; + break; + case EFFECT_ACCURACY_UP: + case EFFECT_ACCURACY_UP_2: + if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_ACC)) + score -= 10; + break; + case EFFECT_EVASION_UP: + case EFFECT_EVASION_UP_2: + case EFFECT_MINIMIZE: + if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_EVASION)) + score -= 10; + break; + case EFFECT_ACUPRESSURE: + if (DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || AreBattlersStatsMaxed(battlerDef) || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) + score -= 10; + break; + case EFFECT_ATTACK_DOWN: + case EFFECT_ATTACK_DOWN_2: + if (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE + || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL) + || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + { + score -= 10; + } + break; + case EFFECT_VENOM_DRENCH: + if (targetSameSide) + score -= 10; + + if (!(gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)) + { + score -= 10; + } + else if (gBattleMons[battlerDef].statStages[STAT_SPEED] == MIN_STAT_STAGE + && (gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) + && (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL))) + { + score -= 10; + } + break; + case EFFECT_NOBLE_ROAR: + if (((gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) + && (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL))) + || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + { + score -= 10; + } + break; + case EFFECT_DEFENSE_DOWN: + case EFFECT_DEFENSE_DOWN_2: + if (gBattleMons[battlerDef].statStages[STAT_DEF] == MIN_STAT_STAGE + || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + score -= 10; + break; + case EFFECT_SPEED_DOWN: + case EFFECT_SPEED_DOWN_2: + if (gBattleMons[battlerDef].statStages[STAT_SPEED] == MIN_STAT_STAGE + || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + score -= 10; + break; + case EFFECT_SPECIAL_ATTACK_DOWN: + case EFFECT_SPECIAL_ATTACK_DOWN_2: + if (gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE + || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + score -= 10; + break; + case EFFECT_CAPTIVATE: + { + u8 atkGender = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerAtk].species, gBattleMons[battlerAtk].personality); + u8 defGender = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerDef].species, gBattleMons[battlerDef].personality); + if (atkGender == MON_GENDERLESS || defGender == MON_GENDERLESS || atkGender == defGender) + score -= 10; + } + break; + case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN_2: + if (gBattleMons[battlerDef].statStages[STAT_SPDEF] == MIN_STAT_STAGE + || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + score -= 10; + break; + case EFFECT_ACCURACY_DOWN: + case EFFECT_ACCURACY_DOWN_2: + if (gBattleMons[battlerDef].statStages[STAT_ACC] == MIN_STAT_STAGE + || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + score -= 10; + break; + case EFFECT_EVASION_DOWN: + case EFFECT_EVASION_DOWN_2: + if (gBattleMons[battlerDef].statStages[STAT_EVASION] == MIN_STAT_STAGE + || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + score -= 10; + break; + case EFFECT_HAZE: + if (PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + { + score -= 10; // partner already using haze + } + else + { + u32 i; + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) + RETURN_SCORE_MINUS(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[battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) + RETURN_SCORE_MINUS(10); //Don't want to reset enemy lowered stats + } + } + break; + case EFFECT_BIDE: + if (!BattlerHasDamagingMove(battlerDef) + || GetHealthPercentage(battlerAtk) < 30 //Close to death + || gBattleMons[battlerDef].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) //No point in biding if can't take damage + score -= 10; + break; + case EFFECT_ROAR: + if (DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + RETURN_SCORE_MINUS(10); // don't scare away pokemon twice + + //Don't blow out a Pokemon that'll faint soon or is taking a a lot of secondary damage + if (GetHealthPercentage(battlerDef) < 10 && BattlerHasSecondaryDamage(battlerDef)) + score -= 10; + else if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) + score -= 10; + + if (CountUsablePartyMons(battlerDef) == 1 + || defAbility == ABILITY_SUCTION_CUPS + || gStatuses3[battlerDef] & STATUS3_ROOTED) + score -= 10; + break; + case EFFECT_HIT_SWITCH_TARGET: + if (DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; // don't scare away pokemon twice + else if (GetHealthPercentage(battlerDef) < 10 && BattlerHasSecondaryDamage(battlerDef)) + score -= 10; // don't blow away mon that will faint soon + else if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) + score -= 10; + break; + case EFFECT_CONVERSION: + //Check first move type + if (IS_BATTLER_OF_TYPE(battlerAtk, gBattleMoves[gBattleMons[battlerAtk].moves[0]].type)) + score -= 10; + break; + case EFFECT_RESTORE_HP: + case EFFECT_REST: + case EFFECT_MORNING_SUN: + if (GetHealthPercentage(battlerAtk) == 100) + score -= 10; + else if (GetHealthPercentage(battlerAtk) >= 90) + 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)) + score -= 10; + else if (battlerDef == battlerAtkPartner) + break; //Always heal your ally + else if (GetHealthPercentage(battlerAtk) == 100) + score -= 10; + else if (GetHealthPercentage(battlerAtk) >= 90) + score -= 8; //No point in healing, but should at least do it if nothing better + break; + case EFFECT_TOXIC_THREAD: + if (gBattleMons[battlerDef].statStages[STAT_SPEED] > MIN_STAT_STAGE && defAbility != ABILITY_CONTRARY) + score -= 10; + //fallthrough + case EFFECT_POISON: + case EFFECT_TOXIC: + if (!AI_ShouldPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + else if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + score -= 10; + break; + case EFFECT_LIGHT_SCREEN: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_LIGHTSCREEN + || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + else if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL) + score--; //can use move, but it doesn't stack with light screen + break; + case EFFECT_REFLECT: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_REFLECT + || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + else if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL) + score--; // can use, but doesn't stack with reflect + break; + case EFFECT_AURORA_VEIL: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL + || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove) + || !(gBattleWeather & WEATHER_HAIL_ANY)) + score -= 10; + else if (gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN)) + score--; // can use, but won't stack + break; + case EFFECT_OHKO: + if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) + score -= 10; + if (!ShouldTryOHKO(battlerAtk, battlerDef, atkAbility, defAbility, accuracy, move)) + score -= 10; + break; + case EFFECT_RECOIL_IF_MISS: + if (atkAbility != ABILITY_MAGIC_GUARD && accuracy < 75) + score -= 6; + break; + case EFFECT_MIST: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST + || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_FOCUS_ENERGY: + if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) + score -= 10; + break; + case EFFECT_RECOIL_25: + if (atkAbility != ABILITY_MAGIC_GUARD && atkAbility != ABILITY_ROCK_HEAD) + { + u32 recoilDmg = max(1, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 4); + if (!ShouldUseRecoilMove(battlerAtk, battlerDef, recoilDmg, AI_THINKING_STRUCT->movesetIndex)) + score -= 10; + break; + } + break; + case EFFECT_RECOIL_33: + case EFFECT_RECOIL_33_STATUS: + if (atkAbility != ABILITY_MAGIC_GUARD && atkAbility != ABILITY_ROCK_HEAD) + { + u32 recoilDmg = max(1, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 3); + if (!ShouldUseRecoilMove(battlerAtk, battlerDef, recoilDmg, AI_THINKING_STRUCT->movesetIndex)) + score -= 10; + break; + } + break; + case EFFECT_RECOIL_50: + if (atkAbility != ABILITY_MAGIC_GUARD && atkAbility != ABILITY_ROCK_HEAD) + { + u32 recoilDmg = max(1, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 2); + if (!ShouldUseRecoilMove(battlerAtk, battlerDef, recoilDmg, AI_THINKING_STRUCT->movesetIndex)) + score -= 10; + break; + } + break; + case EFFECT_CONFUSE: + if (!AI_CanConfuse(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_TEETER_DANCE: + if (((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && defAbility == ABILITY_OWN_TEMPO) + || (IsBattlerGrounded(battlerDef) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + || (DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) + && ((gBattleMons[battlerDefPartner].status2 & STATUS2_CONFUSION) + || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && defPartnerAbility == ABILITY_OWN_TEMPO) + || (IsBattlerGrounded(battlerDefPartner) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + || (DoesSubstituteBlockMove(battlerAtk, battlerDefPartner, move)))) + { + score -= 10; + } + 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 + score -= 10; + break; + case EFFECT_PARALYZE: + if (move != MOVE_GLARE && gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + score -= 10; + else if (AI_CanParalyze(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + break; + case EFFECT_TWO_TURNS_ATTACK: + if (atkHoldEffect != HOLD_EFFECT_POWER_HERB && CanTargetFaintAi(battlerDef, battlerAtk)) + score -= 6; + break; + case EFFECT_SUBSTITUTE: + if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE + || GetHealthPercentage(battlerAtk) <= 25 + || defAbility == ABILITY_INFILTRATOR) + score -= 10; + else if (B_SOUND_SUBSTITUTE >= GEN_6 && TestMoveFlagsInMoveset(battlerDef, FLAG_SOUND)) + score -= 10; + break; + case EFFECT_RECHARGE: + if (atkAbility != ABILITY_TRUANT + && !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex)) + score -= 2; + break; + case EFFECT_SPITE: + case EFFECT_MIMIC: + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + { + if (gLastMoves[battlerDef] == MOVE_NONE + || gLastMoves[battlerDef] == 0xFFFF) + score -= 10; + } + // TODO - if no predicted move, decrease viability + break; + case EFFECT_METRONOME: + break; + case EFFECT_LEECH_SEED: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) + || gStatuses3[battlerDef] & STATUS3_LEECHSEED + || defAbility == ABILITY_LIQUID_OOZE + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_DISABLE: + if (gDisableStructs[battlerDef].disableTimer == 0 + && (B_MENTAL_HERB >= GEN_5 && defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) + && !PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + { + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + { + if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) + score -= 10; + } + //TODO - if predictive move = MOVE_NONE, score -= 10 + } + else + { + score -= 10; + } + break; + case EFFECT_COUNTER: + case EFFECT_MIRROR_COAT: + //TODO - predicted move + /*if (GetBattleMoveSplit(predictedMove) == SPLIT_STATUS + || predictedMove == MOVE_NONE + || DoesSubstituteBlockMove(battlerAtk, battlerDefPartner, predictedMove) + score -= 10;*/ + break; + case EFFECT_ENCORE: + if (gDisableStructs[battlerDef].encoreTimer == 0 + && (B_MENTAL_HERB >= GEN_5 && defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) + && !DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + { + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + { + if (gLastMoves[battlerDef] == MOVE_NONE + || gLastMoves[battlerDef] == 0xFFFF) + score -= 10; + } + //TODO predicted moves + //else if (predictedMove == MOVE_NONE) + //score -= 10; + } + else + { + score -= 10; + } + break; + case EFFECT_ENDEAVOR: + case EFFECT_PAIN_SPLIT: + if (gBattleMons[battlerAtk].hp > (gBattleMons[battlerAtk].hp + gBattleMons[battlerDef].hp) / 2) + score -= 10; + break; + case EFFECT_SNORE: + case EFFECT_SLEEP_TALK: + // AI shouldn't really know if its about to wake up since its random + /*if (((gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) == 1 || !(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP)) + && atkAbility != ABILITY_COMATOSE) + score -= 10;*/ + if (!(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) && atkAbility != ABILITY_COMATOSE) + score -= 10; + break; + case EFFECT_CONVERSION_2: + //TODO + break; + case EFFECT_LOCK_ON: + if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS + || atkAbility == ABILITY_NO_GUARD + || defAbility == ABILITY_NO_GUARD + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_LASER_FOCUS: + if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS) + score -= 10; + else if (defAbility == ABILITY_SHELL_ARMOR || defAbility == ABILITY_BATTLE_ARMOR) + score -= 8; + break; + case EFFECT_SKETCH: + if (gLastMoves[battlerDef] == MOVE_NONE) + score -= 10; + break; + case EFFECT_DESTINY_BOND: + if (gBattleMons[battlerDef].status2 & STATUS2_DESTINY_BOND) + score -= 10; + break; + case EFFECT_FALSE_SWIPE: + // TODO + break; + case EFFECT_HEAL_BELL: + if (!AnyPartyMemberStatused(battlerAtk, TestMoveFlags(move, FLAG_SOUND)) || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_MEAN_LOOK: + if (IsBattlerTrapped(battlerDef, TRUE) + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_HIT_PREVENT_ESCAPE: + break; + case EFFECT_NIGHTMARE: + if (gBattleMons[battlerDef].status2 & STATUS2_NIGHTMARE + || !(gBattleMons[battlerDef].status1 & STATUS1_SLEEP || defAbility == ABILITY_COMATOSE) + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_CURSE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) + { + if (gBattleMons[battlerDef].status2 & STATUS2_CURSED + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + else if (GetHealthPercentage(battlerAtk) <= 50) + score -= 6; + } + else //Regular Curse + { + if (!BattlerStatCanRise(battlerAtk, atkAbility, STAT_ATK) + && !BattlerStatCanRise(battlerAtk, atkAbility, STAT_DEF) + && !BattlerStatCanFall(battlerAtk, atkAbility, STAT_SPEED)) + score -= 10; + } + break; + case EFFECT_ENDURE: + if (gBattleMons[battlerAtk].hp == 1 || BattlerHasSecondaryDamage(battlerAtk)) //Don't use Endure if you'll die after using it + score -= 10; + break; + case EFFECT_PROTECT: + { + bool32 decreased = FALSE; + switch (move) + { + case MOVE_QUICK_GUARD: + case MOVE_WIDE_GUARD: + case MOVE_CRAFTY_SHIELD: + if (!IsValidDoubleBattle(battlerAtk)) + { + score -= 10; + decreased = TRUE; + } + break; + case MOVE_MAT_BLOCK: + if (!gDisableStructs[battlerAtk].isFirstTurn) + { + score -= 10; + decreased = TRUE; + } + break; + } // move check + + if (decreased) + break; + if (gBattleMons[battlerDef].status2 & STATUS2_RECHARGE) + { + score -= 10; + break; + } + + if (gBattleMoves[gLastResultingMoves[battlerAtk]].effect == EFFECT_PROTECT + && move != MOVE_QUICK_GUARD + && move != MOVE_WIDE_GUARD + && move != MOVE_CRAFTY_SHIELD) //These moves have infinite usage + { + if (BattlerHasSecondaryDamage(battlerAtk) + && defAbility != ABILITY_MOXIE + && defAbility != ABILITY_BEAST_BOOST) + { + score -= 10; //Don't protect if you're going to faint after protecting + } + else if (gDisableStructs[battlerAtk].protectUses == 1 && Random() % 100 < 50) + { + if (!IsValidDoubleBattle(battlerAtk)) + score -= 6; + else + score -= 10; //Don't try double protecting in doubles + } + else if (gDisableStructs[battlerAtk].protectUses >= 2) + { + score -= 10; + } + } + + /*if (AI_THINKING_STRUCT->aiFlags == 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_SPIKES: + if (gSideTimers[GetBattlerSide(battlerDef)].spikesAmount >= 3) + score -= 10; + else if (PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove) + && gSideTimers[GetBattlerSide(battlerDef)].spikesAmount == 2) + 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(battlerAtkPartner, move, partnerMove)) //Only one mon needs to set up Stealth Rocks + score -= 10; + break; + case EFFECT_TOXIC_SPIKES: + if (gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount >= 2) + score -= 10; + else if (PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount == 1) + 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) + score -= 10; + else if (PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) + score -= 10; //Only one mon needs to set up Sticky Web + break; + case EFFECT_FORESIGHT: + if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT) + { + score -= 10; + } + else if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 + || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + { + score -= 9; + } + break; + case EFFECT_MIRACLE_EYE: + if (gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED) + score -= 10; + + if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 + || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)) + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 9; + break; + case EFFECT_PERISH_SONG: + if (IsValidDoubleBattle(battlerAtk)) + { + if (CountUsablePartyMons(battlerAtk) <= 2 + && atkAbility != ABILITY_SOUNDPROOF + && atkPartnerAbility != ABILITY_SOUNDPROOF + && CountUsablePartyMons(FOE(battlerAtk)) >= 3) + { + score -= 10; //Don't wipe your team if you're going to lose + } + else if ((!IsBattlerAlive(FOE(battlerAtk)) || AI_GetAbility(FOE(battlerAtk)) == ABILITY_SOUNDPROOF + || gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG) + && (!IsBattlerAlive(BATTLE_PARTNER(FOE(battlerAtk))) || AI_GetAbility(BATTLE_PARTNER(FOE(battlerAtk))) == ABILITY_SOUNDPROOF + || gStatuses3[BATTLE_PARTNER(FOE(battlerAtk))] & STATUS3_PERISH_SONG)) + { + score -= 10; //Both enemies are perish songed + } + else if (DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + } + else + { + if (CountUsablePartyMons(battlerAtk) == 1 && atkAbility != ABILITY_SOUNDPROOF + && CountUsablePartyMons(battlerDef) >= 2) + score -= 10; + + if (gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG || AI_GetAbility(FOE(battlerAtk)) == ABILITY_SOUNDPROOF) + score -= 10; + } + break; + case EFFECT_SANDSTORM: + if (gBattleWeather & WEATHER_SANDSTORM_ANY //TODO | WEATHER_PRIMAL_ANY) + || PartnerMoveEffectIsWeather(battlerAtkPartner, partnerMove)) + score -= 10; + break; + case EFFECT_SUNNY_DAY: + if (gBattleWeather & WEATHER_SUN_ANY //TODO | WEATHER_PRIMAL_ANY) + || PartnerMoveEffectIsWeather(battlerAtkPartner, partnerMove)) + score -= 10; + break; + case EFFECT_RAIN_DANCE: + if (gBattleWeather & WEATHER_RAIN_ANY //TODO | WEATHER_PRIMAL_ANY) + || PartnerMoveEffectIsWeather(battlerAtkPartner, partnerMove)) + score -= 10; + break; + case EFFECT_HAIL: + if (gBattleWeather & WEATHER_HAIL_ANY //TODO | WEATHER_PRIMAL_ANY | WEATHER_CIRCUS) + || PartnerMoveEffectIsWeather(battlerAtkPartner, partnerMove)) + score -= 10; + break; + case EFFECT_SWAGGER: + if (targetSameSide && defAbility == ABILITY_CONTRARY) + score -= 10; + else if (!AI_CanConfuse(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_ATTRACT: + { + u8 atkGender = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerAtk].species, gBattleMons[battlerAtk].personality); + u8 defGender = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerDef].species, gBattleMons[battlerDef].personality); + if (!AI_CanBeInfatuated(battlerAtk, battlerDef, defAbility, atkGender, defGender) + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + } + break; + case EFFECT_SAFEGUARD: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_SAFEGUARD + || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_BURN_UP: + if (!IS_BATTLER_OF_TYPE(battlerAtk, TYPE_FIRE)) + score -= 10; + break; + case EFFECT_PARTING_SHOT: + if (CountUsablePartyMons(battlerAtk) == 1) + score -= 10; + break; + case EFFECT_BATON_PASS: + if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE + || (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING | STATUS3_MAGNET_RISE | STATUS3_POWER_TRICK)) + || AnyStatIsRaised(battlerAtk)) + break; + + score -= 6; + break; + case EFFECT_HIT_ESCAPE: + break; + case EFFECT_RAPID_SPIN: + if ((gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED) || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED)) + break; // check damage/accuracy + + //Spin checks + if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_HAZARDS_ANY)) + score -= 6; + 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_HAZARDS_ANY) + { + if (PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + { + score -= 10; //Only need one hazards removal + break; + } + } + + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_HAZARDS_ANY) + { + score -= 10; //Don't blow away opposing hazards + break; + } + + if (IsValidDoubleBattle(battlerAtk)) + { + if (IsHazardMoveEffect(gBattleMoves[partnerMove].effect) // partner is going to set up hazards + && GetWhoStrikesFirst(battlerAtkPartner, battlerAtk, FALSE)) // partner is going to set up before the potential Defog + { + 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 + || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + score -= 10; + break; + case EFFECT_BELLY_DRUM: + if (atkAbility == ABILITY_CONTRARY) + score -= 10; + else if (GetHealthPercentage(battlerAtk) <= 60) + score -= 10; + break; + case EFFECT_PSYCH_UP: // haze stats check + { + u32 i; + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) + RETURN_SCORE_MINUS(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[battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) + RETURN_SCORE_MINUS(10); //Don't want to copy enemy lowered stats + } + } + break; + case EFFECT_SPECTRAL_THIEF: + break; + case EFFECT_FUTURE_SIGHT: + if (gWishFutureKnock.futureSightCounter[battlerDef] != 0) + score -= 10; + break; + case EFFECT_SOLARBEAM: + if (atkHoldEffect == HOLD_EFFECT_POWER_HERB + || (AI_WeatherHasEffect() && gBattleWeather & WEATHER_SUN_ANY && atkHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA)) + break; + if (CanTargetFaintAi(battlerDef, battlerAtk)) //Attacker can be knocked out + score -= 4; + break; + case EFFECT_SEMI_INVULNERABLE: + //TODO - predicted moves + /*if (predictedMove != MOVE_NONE + && MoveWouldHitFirst(move, battlerAtk, battlerDef) + && gBattleMoves[predictedMove].effect == EFFECT_SEMI_INVULNERABLE) + score -= 10;*/ // Don't Fly if opponent is going to fly after you + + if (BattlerWillFaintFromWeather(battlerAtk, atkAbility) + && (move == MOVE_FLY || move == MOVE_BOUNCE)) + score -= 10; // Attacker will faint while in the air + break; + case EFFECT_FAKE_OUT: + // first impression check + if (!gDisableStructs[battlerAtk].isFirstTurn) + { + score -= 10; + } + else if (move == MOVE_FAKE_OUT) + { + if ((atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || atkAbility == ABILITY_GORILLA_TACTICS) + && (CountUsablePartyMons(battlerDef) >= 2 || !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex))) + { + if (CountUsablePartyMons(battlerAtk) == 1) + score -= 10; // Don't lock the attacker into Fake Out if they can't switch out afterwards. + } + } + break; //damage checks + case EFFECT_STOCKPILE: + if (gDisableStructs[battlerAtk].stockpileCounter >= 3) + score -= 10; + break; + case EFFECT_SPIT_UP: + if (gDisableStructs[battlerAtk].stockpileCounter == 1) + score -= 10; + else if (gDisableStructs[battlerAtk].stockpileCounter <= 1) + score -= 2; + break; + case EFFECT_SWALLOW: + if (gDisableStructs[battlerAtk].stockpileCounter == 0) + { + score -= 10; + } + else + { + if (GetHealthPercentage(battlerAtk) == 100) + score -= 10; + else if (GetHealthPercentage(battlerAtk) >= 80) + score -= 5; // do it if nothing better + } + break; + case EFFECT_TORMENT: + if (gBattleMons[battlerDef].status2 & STATUS2_TORMENT + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + { + score -= 10; + break; + } + + if (B_MENTAL_HERB >= GEN_5 && defHoldEffect == HOLD_EFFECT_CURE_ATTRACT) + score -= 6; + break; + case EFFECT_FLATTER: + if (targetSameSide && defAbility == ABILITY_CONTRARY) + score -= 10; + else if (!AI_CanConfuse(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_WILL_O_WISP: + if (!AI_CanBurn(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_MEMENTO: + if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + else if (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE && gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE) + score -= 10; + break; + case EFFECT_HEALING_WISH: //healing wish, lunar dance + if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + else if (IsPartyFullyHealedExceptBattler(battlerAtk)) + score -= 10; + break; + case EFFECT_FINAL_GAMBIT: + if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_FOCUS_PUNCH: + //TODO predicted moves + /*if (predictedMove != MOVE_NONE + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, predictedMove) + && SPLIT(predictedMove) != SPLIT_STATUS + && gBattleMoves[predictedMove].power != 0) + score -= 10;*/ //Probably better not to use it + break; + //TODO + // case EFFECT_SHELL_TRAP: + // case EFFECT_BEAK_BLAST: + case EFFECT_NATURE_POWER: + return AI_CheckBadMove(battlerAtk, battlerDef, GetNaturePowerMove(), originalScore); + case EFFECT_CHARGE: + if (gStatuses3[battlerAtk] & STATUS3_CHARGED_UP) + { + score -= 10; + break; + } + else if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC)) + { + if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPDEF)) + score -= 10; + } + break; + case EFFECT_TAUNT: + if (gDisableStructs[battlerDef].tauntTimer > 0 + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + score--; + break; + case EFFECT_FOLLOW_ME: + case EFFECT_HELPING_HAND: + if (!IsValidDoubleBattle(battlerAtk) + || !IsBattlerAlive(battlerAtkPartner) + || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove) + || (partnerMove != MOVE_NONE && IS_MOVE_STATUS(partnerMove)) + || *(gBattleStruct->monToSwitchIntoId + battlerAtkPartner) != PARTY_SIZE) //Partner is switching out. + score -= 10; + break; + case EFFECT_TRICK: + if ((atkHoldEffect == HOLD_EFFECT_NONE && defHoldEffect == HOLD_EFFECT_NONE) + || defAbility == ABILITY_STICKY_HOLD + || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item) + || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerDef].item) + || !CanBattlerGetOrLoseItem(battlerDef, gBattleMons[battlerAtk].item) + || !CanBattlerGetOrLoseItem(battlerDef, gBattleMons[battlerDef].item)) + score -= 10; // kinda cheating with battlerDef item check, but only item effects recorded + break; + case EFFECT_BESTOW: + if (atkHoldEffect == HOLD_EFFECT_NONE + || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item)) // AI knows its own item + score -= 10; + break; + case EFFECT_ROLE_PLAY: + if (atkAbility == defAbility + || defAbility == ABILITY_NONE + || IsRolePlayBannedAbilityAtk(atkAbility) + || IsRolePlayBannedAbility(defAbility)) + score -= 10; + break; + case EFFECT_WISH: + if (gWishFutureKnock.wishCounter[battlerAtk] != 0) + score -= 10; + break; + case EFFECT_ASSIST: + if (CountUsablePartyMons(battlerAtk) == 1) + score -= 10; // no teammates to assist from + break; + case EFFECT_INGRAIN: + if (gStatuses3[battlerAtk] & STATUS3_ROOTED) + score -= 10; + break; + case EFFECT_AQUA_RING: + if (gStatuses3[battlerAtk] & STATUS3_AQUA_RING) + score -= 10; + break; + case EFFECT_SUPERPOWER: + #ifdef POKEMON_EXPANSION + if (move == MOVE_HYPERSPACE_FURY && gBattleMons[battlerAtk].species != SPECIES_HOOPA_UNBOUND) + score -= 10; + #endif + break; + case EFFECT_MAGIC_COAT: + if (!TestMoveFlagsInMoveset(battlerDef, FLAG_MAGICCOAT_AFFECTED)) + score -= 10; + break; + case EFFECT_RECYCLE: + if (gBattleStruct->usedHeldItems[battlerAtk] == 0 || gBattleMons[battlerAtk].item != 0) + score -= 10; + break; + case EFFECT_BELCH: + if (ItemId_GetPocket(gBattleStruct->usedHeldItems[battlerAtk]) != POCKET_BERRIES) + score -= 10; // attacker has not consumed a berry + break; + case EFFECT_YAWN: + if (gStatuses3[battlerDef] & STATUS3_YAWN) + score -= 10; + else if (!AI_ShouldPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + break; + case EFFECT_KNOCK_OFF: + /*if (defHoldEffect == HOLD_EFFECT_ASSAULT_VEST + || (defHoldEffect == HOLD_EFFECT_CHOICE_BAND && atkAbility != ABILITY_GORILLA_TACTICS && gBattleStruct->choicedMove[battlerDef])) + { + if (GetStrongestMove(battlerDef, battlerAtk) == MOVE_NONE + || AI_SpecialTypeCalc(GetStrongestMove(battlerDef, battlerAtk), battlerDef, battlerAtk) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) + DECREASE_VIABILITY(9); //Don't use Knock Off is the enemy's only moves don't affect the AI + }*/ + if (defHoldEffect == HOLD_EFFECT_NONE) + score -= 4; + break; + case EFFECT_SKILL_SWAP: + if (atkAbility == ABILITY_NONE || defAbility == ABILITY_NONE + || IsSkillSwapBannedAbility(atkAbility) || IsSkillSwapBannedAbility(defAbility)) + score -= 10; + break; + case EFFECT_WORRY_SEED: + if (defAbility == ABILITY_INSOMNIA + || IsWorrySeedBannedAbility(defAbility)) + score -= 10; + break; + case EFFECT_GASTRO_ACID: + if (gStatuses3[battlerDef] & STATUS3_GASTRO_ACID + || IsGastroAcidBannedAbility(defAbility)) + score -= 10; + break; + case EFFECT_ENTRAINMENT: + if (atkAbility == ABILITY_NONE + || IsEntrainmentBannedAbilityAttacker(atkAbility) + || IsEntrainmentTargetOrSimpleBeamBannedAbility(defAbility)) + score -= 10; + break; + case EFFECT_CORE_ENFORCER: + break; + case EFFECT_SIMPLE_BEAM: + if (defAbility == ABILITY_SIMPLE + || IsEntrainmentTargetOrSimpleBeamBannedAbility(defAbility)) + score -= 10; + break; + case EFFECT_IMPRISON: + if (gStatuses3[battlerAtk] & STATUS3_IMPRISONED_OTHERS) + score -= 10; + break; + case EFFECT_REFRESH: + if (!(gBattleMons[battlerDef].status1 & (STATUS1_PSN_ANY | STATUS1_BURN | STATUS1_PARALYSIS))) + score -= 10; + break; + case EFFECT_PSYCHO_SHIFT: + if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_ShouldPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && !AI_CanBurn(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + score -= 10; + else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_ShouldPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + else + score -= 10; + break; + case EFFECT_SNATCH: + if (!TestMoveFlagsInMoveset(battlerDef, FLAG_SNATCH_AFFECTED) + || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_MUD_SPORT: + if (gFieldStatuses & STATUS_FIELD_MUDSPORT + || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_WATER_SPORT: + if (gFieldStatuses & STATUS_FIELD_WATERSPORT + || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_TICKLE: + if ((defAbility == ABILITY_CONTRARY) && !targetSameSide) + score -= 10; + else if ((gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) + && gBattleMons[battlerDef].statStages[STAT_DEF] == MIN_STAT_STAGE) + score -= 10; + break; + case EFFECT_COSMIC_POWER: + if (atkAbility == ABILITY_CONTRARY) + score -= 10; + else if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE + && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) + score -= 10; + break; + // TODO + /*case EFFECT_NO_RETREAT: + if (TrappedByNoRetreat(battlerAtk)) + score -= 10; + break; + case EFFECT_EXTREME_EVOBOOST: + if (MainStatsMaxed(battlerAtk)) + score -= 10; + break; + case EFFECT_CLANGOROUS_SOUL: + if (gBattleMons[battlerAtk].hp <= gBattleMons[battlerAtk].maxHP / 3) + score -= 10; + break;*/ + case EFFECT_BULK_UP: + if (atkAbility == ABILITY_CONTRARY) + score -= 10; + else if ((gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + && gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE) + score -= 10; + break; + case EFFECT_COIL: + if (atkAbility == ABILITY_CONTRARY) + score -= 10; + else if (gBattleMons[battlerAtk].statStages[STAT_ACC] >= MAX_STAT_STAGE + && (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + && gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE) + score -= 10; + break; + case EFFECT_CALM_MIND: + if (atkAbility == ABILITY_CONTRARY) + score -= 10; + else if ((gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) + score -= 10; + break; + case EFFECT_QUIVER_DANCE: + case EFFECT_GEOMANCY: + if (atkAbility == ABILITY_CONTRARY) + score -= 10; + else if (gBattleMons[battlerAtk].statStages[STAT_SPEED] >= MAX_STAT_STAGE + && (gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) + score -= 10; + break; + case EFFECT_DRAGON_DANCE: + case EFFECT_SHIFT_GEAR: + if (atkAbility == ABILITY_CONTRARY) + score -= 10; + else if ((gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + && (gBattleMons[battlerAtk].statStages[STAT_SPEED] >= MAX_STAT_STAGE)) + score -= 10; + break; + case EFFECT_SHELL_SMASH: + if (atkAbility == ABILITY_CONTRARY) + { + if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE + && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) + score -= 10; + } + else + { + if ((gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + && (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + && (gBattleMons[battlerAtk].statStages[STAT_SPEED] >= MAX_STAT_STAGE)) + score -= 10; + } + break; + + case EFFECT_POWER_TRICK: + if (targetSameSide) + score -= 10; + else if (gBattleMons[battlerAtk].defense >= gBattleMons[battlerAtk].attack && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + score -= 10; + break; + case EFFECT_POWER_SWAP: // Don't use if attacker's stat stages are higher than opponents + if (targetSameSide) + score -= 10; + else if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= gBattleMons[battlerDef].statStages[STAT_ATK] + && gBattleMons[battlerAtk].statStages[STAT_SPATK] >= gBattleMons[battlerDef].statStages[STAT_SPATK]) + score -= 10; + break; + case EFFECT_GUARD_SWAP: // Don't use if attacker's stat stages are higher than opponents + if (targetSameSide) + score -= 10; + else if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= gBattleMons[battlerDef].statStages[STAT_DEF] + && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= gBattleMons[battlerDef].statStages[STAT_SPDEF]) + score -= 10; + break; + case EFFECT_SPEED_SWAP: + if (targetSameSide) + { + score -= 10; + } + else + { + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && (gBattleMons[battlerAtk].speed <= gBattleMons[battlerDef].speed)) + score -= 10; + else if (gBattleMons[battlerAtk].speed >= gBattleMons[battlerDef].speed) + score -= 10; + } + break; + case EFFECT_HEART_SWAP: + if (targetSameSide) + { + score -= 10; + } + else + { + u32 atkPositiveStages = CountPositiveStatStages(battlerAtk); + u32 atkNegativeStages = CountNegativeStatStages(battlerAtk); + u32 defPositiveStages = CountPositiveStatStages(battlerDef); + u32 defNegativeStages = CountNegativeStatStages(battlerDef); + + if (atkPositiveStages >= defPositiveStages && atkNegativeStages <= defNegativeStages) + score -= 10; + break; + } + break; + case EFFECT_POWER_SPLIT: + if (targetSameSide) + { + score -= 10; + } + else + { + u8 atkAttack = gBattleMons[battlerAtk].attack; + u8 defAttack = gBattleMons[battlerDef].attack; + u8 atkSpAttack = gBattleMons[battlerAtk].spAttack; + u8 defSpAttack = gBattleMons[battlerDef].spAttack; + + if (atkAttack + atkSpAttack >= defAttack + defSpAttack) // Combined attacker stats are > than combined target stats + score -= 10; + break; + } + break; + case EFFECT_GUARD_SPLIT: + if (targetSameSide) + { + score -= 10; + } + else + { + u8 atkDefense = gBattleMons[battlerAtk].defense; + u8 defDefense = gBattleMons[battlerDef].defense; + u8 atkSpDefense = gBattleMons[battlerAtk].spDefense; + u8 defSpDefense = gBattleMons[battlerDef].spDefense; + + if (atkDefense + atkSpDefense >= defDefense + defSpDefense) //Combined attacker stats are > than combined target stats + score -= 10; + break; + } + break; + case EFFECT_ME_FIRST: + //TODO - predicted move + /*if (predictedMove != MOVE_NONE) + { + if (!MoveWouldHitFirst(move, battlerAtk, battlerDef)) + score -= 10; + else + return AIScript_Negatives(battlerAtk, battlerDef, predictedMove, originalViability, data); + } + else //Target is predicted to switch most likely + score -= 10;*/ + break; + case EFFECT_NATURAL_GIFT: + if (atkAbility == ABILITY_KLUTZ + || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM + || GetPocketByItemId(gBattleMons[battlerAtk].item) != POCKET_BERRIES) + score -= 10; + break; + case EFFECT_GRASSY_TERRAIN: + if (PartnerMoveEffectIsTerrain(battlerAtkPartner, partnerMove) || gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) + score -= 10; + break; + case EFFECT_ELECTRIC_TERRAIN: + if (PartnerMoveEffectIsTerrain(battlerAtkPartner, partnerMove) || gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + score -= 10; + break; + case EFFECT_PSYCHIC_TERRAIN: + if (PartnerMoveEffectIsTerrain(battlerAtkPartner, partnerMove) || gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + score -= 10; + break; + case EFFECT_MISTY_TERRAIN: + if (PartnerMoveEffectIsTerrain(battlerAtkPartner, partnerMove) || gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + score -= 10; + break; + case EFFECT_PLEDGE: + if (IsValidDoubleBattle(battlerAtk) && gBattleMons[battlerAtkPartner].hp > 0) + { + if (partnerMove != MOVE_NONE + && gBattleMoves[partnerMove].effect == EFFECT_PLEDGE + && move != partnerMove) // Different pledge moves + { + if (gBattleMons[battlerAtkPartner].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) + // && gBattleMons[battlerAtkPartner].status1 != 1) // Will wake up this turn - how would AI know + score -= 10; // Don't use combo move if your partner will cause failure + } + } + break; + case EFFECT_TRICK_ROOM: + if (PartnerMoveIs(battlerAtkPartner, partnerMove, MOVE_TRICK_ROOM)) + { + score -= 10; + } + else if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM) // Trick Room Up + { + if (GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) // Attacker side slower than target side + score -= 10; // Keep the Trick Room up + } + else + { + if (GetBattlerSideSpeedAverage(battlerAtk) > GetBattlerSideSpeedAverage(battlerDef)) // Attacker side faster than target side + score -= 10; // Keep the Trick Room down + } + break; + case EFFECT_MAGIC_ROOM: + if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_WONDER_ROOM: + if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_GRAVITY: + if ((gFieldStatuses & STATUS_FIELD_GRAVITY + && !IS_BATTLER_OF_TYPE(battlerAtk, TYPE_FLYING) + && atkHoldEffect != HOLD_EFFECT_AIR_BALLOON) // Should revert Gravity in this case + || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_ION_DELUGE: + if (gFieldStatuses & STATUS_FIELD_ION_DELUGE + || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + //TODO + //case EFFECT_PLASMA_FISTS: + //break; + case EFFECT_FLING: + if (!CanFling(battlerAtk)) + score -= 10; + else + { + /* TODO + u8 effect = gFlingTable[gBattleMons[battlerAtk].item].effect; + switch (effect) + { + case MOVE_EFFECT_BURN: + if (!AI_CanBurn(battlerAtk, battlerDef, battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case MOVE_EFFECT_PARALYSIS: + if (!AI_CanParalyze(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + break; + case MOVE_EFFECT_POISON: + if (!AI_ShouldPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + break; + case MOVE_EFFECT_TOXIC: + if (!AI_ShouldPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score -= 10; + break; + case MOVE_EFFECT_FREEZE: + if (!CanBeFrozen(battlerDef, TRUE) + || MoveBlockedBySubstitute(move, battlerAtk, battlerDef)) + score -= 10; + break; + }*/ + } + break; + case EFFECT_EMBARGO: + if (defAbility == ABILITY_KLUTZ + || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM + || gDisableStructs[battlerDef].embargoTimer != 0 + || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_POWDER: + if (!HasMoveWithType(battlerDef, TYPE_FIRE) + || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_TELEKINESIS: + if (gStatuses3[battlerDef] & (STATUS3_TELEKINESIS | STATUS3_ROOTED | STATUS3_SMACKED_DOWN) + || gFieldStatuses & STATUS_FIELD_GRAVITY + || defHoldEffect == HOLD_EFFECT_IRON_BALL + || IsTelekinesisBannedSpecies(gBattleMons[battlerDef].species) + || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_THROAT_CHOP: + break; + case EFFECT_HEAL_BLOCK: + if (gDisableStructs[battlerDef].healBlockTimer != 0 + || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_SOAK: + if (PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove) + || (gBattleMons[battlerDef].type1 == TYPE_WATER + && gBattleMons[battlerDef].type2 == TYPE_WATER + && gBattleMons[battlerDef].type3 == TYPE_MYSTERY)) + 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(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case MOVE_FORESTS_CURSE: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + } + break; + case EFFECT_HIT_ENEMY_HEAL_ALLY: // pollen puff + if (targetSameSide) + { + if (GetHealthPercentage(battlerDef) == 100) + score -= 10; + else if (gBattleMons[battlerDef].hp > gBattleMons[battlerDef].maxHP / 2) + score -= 5; + break; + } + // fallthrough + case EFFECT_HEAL_PULSE: // and floral healing + if (!targetSameSide) // Don't heal enemies + { + score -= 10; + } + else + { + if (GetHealthPercentage(battlerDef) == 100) + score -= 10; + else if (gBattleMons[battlerDef].hp > gBattleMons[battlerDef].maxHP / 2) + score -= 5; + } + break; + case EFFECT_ELECTRIFY: + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 + //|| GetMoveTypeSpecial(battlerDef, predictedMove) == TYPE_ELECTRIC // Move will already be electric type + || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_TOPSY_TURVY: + if (!targetSameSide) + { + u8 targetPositiveStages = CountPositiveStatStages(battlerDef); + u8 targetNegativeStages = CountNegativeStatStages(battlerDef); + + if (targetPositiveStages == 0 //No good stat changes to make bad + || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + + else if (targetNegativeStages < targetPositiveStages) + score -= 5; //More stages would be made positive than negative + } + break; + case EFFECT_FAIRY_LOCK: + if ((gFieldStatuses & STATUS_FIELD_FAIRY_LOCK) || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_DO_NOTHING: + score -= 10; + break; + case EFFECT_INSTRUCT: + { + u16 instructedMove; + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) + instructedMove = MOVE_NONE; //TODO instructedMove = predictedMove; + else + instructedMove = gLastMoves[battlerDef]; + + if (instructedMove == MOVE_NONE + || IsInstructBannedMove(instructedMove) + || MoveRequiresRecharging(instructedMove) + || MoveCallsOtherMove(instructedMove) + #ifdef ITEM_Z_RING + || (IsZMove(instructedMove)) + #endif + || (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF) + || gBattleMons[battlerDef].status2 & STATUS2_MULTIPLETURNS + || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + { + score -= 10; + } + else if (IsValidDoubleBattle(battlerAtk)) + { + if (!targetSameSide) + score -= 10; + } + else + { + if (gBattleMoves[instructedMove].target & (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) + 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) + score -= 5; //Do something better + } + } + break; + case EFFECT_QUASH: + if (!IsValidDoubleBattle(battlerAtk) + || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 + || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_AFTER_YOU: + if (!targetSameSide + || !IsValidDoubleBattle(battlerAtk) + || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 + || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + score -= 10; + break; + case EFFECT_SUCKER_PUNCH: + /*TODO predicted move + if (predictedMove != MOVE_NONE) + { + if (IS_MOVE_STATUS(predictedMove) + || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 + { + score -= 10; + break; + } + }*/ + break; + case EFFECT_TAILWIND: + if (gSideTimers[GetBattlerSide(battlerAtk)].tailwindTimer != 0 + || PartnerMoveIs(battlerAtkPartner, partnerMove, MOVE_TAILWIND) + || (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1)) // Trick Room active and not ending this turn + score -= 10; + break; + case EFFECT_LUCKY_CHANT: + if (gSideTimers[GET_BATTLER_SIDE(battlerAtk)].luckyChantTimer != 0 + || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + score -= 10; + break; + case EFFECT_MAGNET_RISE: + if (gFieldStatuses & STATUS_FIELD_GRAVITY + || gDisableStructs[battlerAtk].magnetRiseTimer != 0 + || atkHoldEffect == HOLD_EFFECT_IRON_BALL + || gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_MAGNET_RISE | STATUS3_SMACKED_DOWN) + || !IsBattlerGrounded(battlerAtk)) + score -= 10; + break; + case EFFECT_CAMOUFLAGE: + if (!CanCamouflage(battlerAtk)) + score -= 10; + break; + case EFFECT_LAST_RESORT: + if (!CanUseLastResort(battlerAtk)) + score -= 10; + break; + //TODO + /*case EFFECT_SKY_DROP: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING)) + score -= 10; + if (WillFaintFromWeather(battlerAtk) + || MoveBlockedBySubstitute(move, battlerAtk, battlerDef) + || GetSpeciesWeight(gBattleMons[battlerDef].species, defAbility, defHoldEffect, battlerDef, TRUE) >= 2000) //200.0 kg + score -= 10; + break; + */ + case EFFECT_SYNCHRONOISE: + //Check holding ring target or is of same type + if (defHoldEffect == HOLD_EFFECT_RING_TARGET + || IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type1) + || IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type2) + || IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type3)) + break; + else + score -= 10; + break; + + } // move effect checks + + // substitute check + if (IS_MOVE_STATUS(move) && DoesSubstituteBlockMove(battlerAtk, battlerDef, move)) + score -= 10; + + // damage check + if (!IS_MOVE_STATUS(move)) + { + if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) + score -= 15; + + if (effectiveness < AI_EFFECTIVENESS_x1) + score -= 4; + } + + // helping hand check + if (IsValidDoubleBattle(battlerAtk) && partnerMove != MOVE_NONE + && gBattleMoves[partnerMove].effect == EFFECT_HELPING_HAND + && IS_MOVE_STATUS(move)) + score -= 10; //Don't use a status move if partner wants to help + + if (score < 0) + return 0; //essentially 'dont use this move' + + return score; } static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { s32 dmg; u8 result; - u8 score = originalScore; + s16 score = originalScore; - if (GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef)) - return originalScore; // don't try to faint your ally + if (IsTargetingPartner(battlerAtk, battlerDef)) + return originalScore; // don't try to faint your ally ever if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power == 0) return originalScore; // can't make anything faint with no power - - dmg = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][AI_THINKING_STRUCT->movesetIndex]; - if (gBattleMons[gBattlerTarget].hp <= dmg && gBattleMoves[move].effect != EFFECT_EXPLOSION) + + if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) && gBattleMoves[move].effect != EFFECT_EXPLOSION) { // AI_TryToFaint_Can - if (IsBattlerFaster(AI_CHECK_FASTER) || gBattleMoves[move].flags & FLAG_HIGH_CRIT) + if (IsBattlerFaster(AI_CHECK_FASTER) || TestMoveFlags(move, FLAG_HIGH_CRIT)) score += 4; else score += 2; @@ -2541,7 +4431,7 @@ static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore if (GetMovePowerResult(move) == MOVE_POWER_DISCOURAGED) return (score - 1); - if (GetMoveEffectiveness(move) == AI_EFFECTIVENESS_x4) + if (AI_GetMoveEffectiveness(move) == AI_EFFECTIVENESS_x4) { // AI_TryToFaint_DoubleSuperEffective if ((Random() % 256) >= 80) @@ -2550,7 +4440,7 @@ static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore } //AI_TryToFaint_CheckIfDanger - if (!IsBattlerFaster(AI_CHECK_FASTER) && CanTargetFaintAi()) + if (!IsBattlerFaster(AI_CHECK_FASTER) && CanTargetFaintAi(battlerDef, battlerAtk)) { // AI_TryToFaint_Danger if (GetMovePowerResult(move) != MOVE_POWER_BEST) score--; @@ -2563,6 +4453,7 @@ static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { + } static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) @@ -2612,20 +4503,20 @@ static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { u8 safariFleeRate = gBattleStruct->safariEscapeFactor * 5; // Safari flee rate, from 0-20. - if ((Random() % 100) < safariFleeRate) - AI_Flee(); - else - AI_Watch(); + if ((Random() % 100) < safariFleeRate) + AI_Flee(); + else + AI_Watch(); - return originalScore; + return originalScore; } static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { if (GetHealthPercentage(battlerDef) <= 20) - AI_Flee(); + AI_Flee(); - return originalScore; + return originalScore; } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 3a62c02b54..0fa9509a1f 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -35,6 +35,76 @@ static const u16 sDiscouragedPowerfulMoveEffects[] = 0xFFFF }; +static const u16 sIgnoreMoldBreakerMoves[] = +{ + MOVE_MOONGEIST_BEAM, + MOVE_SUNSTEEL_STRIKE, + MOVE_PHOTON_GEYSER, + #ifdef MOVE_LIGHT_THAT_BURNS_THE_SKY + MOVE_LIGHT_THAT_BURNS_THE_SKY, + #endif + #ifdef MOVE_MENACING_MOONRAZE_MAELSTROM + MOVE_MENACING_MOONRAZE_MAELSTROM, + #endif + #ifdef MOVE_SEARING_SUNRAZE_SMASH + MOVE_SEARING_SUNRAZE_SMASH, + #endif +}; + +static const u16 sInstructBannedMoves[] = +{ + MOVE_INSTRUCT, + MOVE_BIDE, + MOVE_FOCUS_PUNCH, + MOVE_BEAK_BLAST, + MOVE_SHELL_TRAP, + MOVE_SKETCH, + MOVE_TRANSFORM, + MOVE_MIMIC, + MOVE_KINGS_SHIELD, + MOVE_STRUGGLE, + MOVE_BOUNCE, + MOVE_DIG, + MOVE_DIVE, + MOVE_FLY, + MOVE_FREEZE_SHOCK, + MOVE_GEOMANCY, + MOVE_ICE_BURN, + MOVE_PHANTOM_FORCE, + MOVE_RAZOR_WIND, + MOVE_SHADOW_FORCE, + MOVE_SKULL_BASH, + MOVE_SKY_ATTACK, + MOVE_SKY_DROP, + MOVE_SOLAR_BEAM, + MOVE_SOLAR_BLADE, +}; + +static const u16 sRechargeMoves[] = +{ + MOVE_HYPER_BEAM, + MOVE_BLAST_BURN, + MOVE_HYDRO_CANNON, + MOVE_FRENZY_PLANT, + MOVE_GIGA_IMPACT, + MOVE_ROCK_WRECKER, + MOVE_ROAR_OF_TIME, + MOVE_PRISMATIC_LASER, + MOVE_METEOR_ASSAULT, + MOVE_ETERNABEAM, +}; + +static const u16 sOtherMoveCallingMoves[] = +{ + MOVE_ASSIST, + MOVE_COPYCAT, + MOVE_ME_FIRST, + MOVE_METRONOME, + MOVE_MIRROR_MOVE, + MOVE_NATURE_POWER, + MOVE_SLEEP_TALK, +}; + // Functions void RecordLastUsedMoveByTarget(void) { @@ -171,38 +241,38 @@ void RestoreBattlerData(u8 battlerId) u32 GetHealthPercentage(u8 battlerId) { - return (u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP); + return (u32)((100 * gBattleMons[battlerId].hp) / gBattleMons[battlerId].maxHP); } -bool32 IsBattlerTrapped(u8 battler, bool8 switching) +bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch) { - u8 holdEffect = GetBattlerHoldEffect(battler, TRUE); - if (IS_BATTLER_OF_TYPE(battler, TYPE_GHOST) - || (switching && holdEffect == HOLD_EFFECT_SHED_SHELL) - || (!switching && GetBattlerAbility(battler) == ABILITY_RUN_AWAY) - || (!switching && holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)) + u8 holdEffect = AI_GetHoldEffect(battler); + if (IS_BATTLER_OF_TYPE(battler, TYPE_GHOST) + || (checkSwitch && holdEffect == HOLD_EFFECT_SHED_SHELL) + || (!checkSwitch && GetBattlerAbility(battler) == ABILITY_RUN_AWAY) + || (!checkSwitch && holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)) { - return FALSE; + return FALSE; } - else - { - if (gBattleMons[battler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED) + else + { + if (gBattleMons[battler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED) || IsAbilityPreventingEscape(battler) - || gStatuses3[battler] & (STATUS3_ROOTED) // TODO: sky drop target in air - || (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK)) - return TRUE; - } + || gStatuses3[battler] & (STATUS3_ROOTED) // TODO: sky drop target in air + || (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK)) + return TRUE; + } - return FALSE; + return FALSE; } // Checks if one of the moves has side effects or perks static u32 WhichMoveBetter(u32 move1, u32 move2) { - s32 defAbility = AI_GetAbility(gBattlerTarget, FALSE); + s32 defAbility = AI_GetAbility(gBattlerTarget); // Check if physical moves hurt. - if (GetBattlerHoldEffect(sBattler_AI, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS + if (AI_GetHoldEffect(sBattler_AI) != HOLD_EFFECT_PROTECTIVE_PADS && (BATTLE_HISTORY->itemEffects[gBattlerTarget] == HOLD_EFFECT_ROCKY_HELMET || defAbility == ABILITY_IRON_BARBS || defAbility == ABILITY_ROUGH_SKIN)) { @@ -354,7 +424,7 @@ u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) return typeEffectiveness; } -u8 GetMoveEffectiveness(u16 move) +u8 AI_GetMoveEffectiveness(u16 move) { u8 damageVar; u32 effectivenessMultiplier; @@ -437,16 +507,16 @@ bool32 IsBattlerFaster(u8 battler) } // Check if target has means to faint ai mon. -bool32 CanTargetFaintAi(void) +bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk) { s32 i, dmg; - u32 unusable = CheckMoveLimitations(gBattlerTarget, 0, 0xFF & ~MOVE_LIMITATION_PP); - u16 *moves = gBattleResources->battleHistory->usedMoves[gBattlerTarget]; + u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP); + u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i]) - && AI_CalcDamage(moves[i], gBattlerTarget, sBattler_AI) >= gBattleMons[sBattler_AI].hp) + && AI_CalcDamage(moves[i], battlerDef, battlerAtk) >= gBattleMons[battlerAtk].hp) { return TRUE; } @@ -455,13 +525,14 @@ bool32 CanTargetFaintAi(void) return FALSE; } -s32 AI_GetAbility(u32 battlerId, bool32 guess) +// does NOT include ability suppression checks +s32 AI_GetAbility(u32 battlerId) { // The AI knows its own ability. if (IsBattlerAIControlled(battlerId)) return gBattleMons[battlerId].ability; - if (BATTLE_HISTORY->abilities[battlerId] != 0) + if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE) return BATTLE_HISTORY->abilities[battlerId]; // Abilities that prevent fleeing. @@ -475,14 +546,1013 @@ s32 AI_GetAbility(u32 battlerId, bool32 guess) if (gBaseStats[gBattleMons[battlerId].species].abilities[1] != ABILITY_NONE) { // AI has no knowledge of opponent, so it guesses which ability. - if (guess) - return gBaseStats[gBattleMons[battlerId].species].abilities[Random() & 1]; + return gBaseStats[gBattleMons[battlerId].species].abilities[Random() & 1]; } else { return gBaseStats[gBattleMons[battlerId].species].abilities[0]; // It's definitely ability 1. } } - return -1; // Unknown. + return ABILITY_NONE; // Unknown. +} + +u16 AI_GetHoldEffect(u32 battlerId) +{ + u32 holdEffect; + + if (!IsBattlerAIControlled(battlerId)) + holdEffect = BATTLE_HISTORY->itemEffects[battlerId]; + else + holdEffect = GetBattlerHoldEffect(battlerId, FALSE); + + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_AWARE) + { + if (gStatuses3[battlerId] & STATUS3_EMBARGO) + return HOLD_EFFECT_NONE; + if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) + return HOLD_EFFECT_NONE; + if (AI_GetAbility(battlerId) == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) + return HOLD_EFFECT_NONE; + } +} + +// different from IsBattlerGrounded in that we don't always know battler's hold effect or ability +bool32 AI_IsBattlerGrounded(u8 battlerId) +{ + u32 holdEffect = AI_GetHoldEffect(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_GetAbility(battlerId) == ABILITY_LEVITATE) + return FALSE; + else if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING)) + return FALSE; + else + return TRUE; +} + +bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move) +{ + u32 i; + + if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_AWARE)) + return FALSE; // AI doesn't understand ability suppression concept + + for (i = 0; i < ARRAY_COUNT(sIgnoreMoldBreakerMoves); i++) + { + if (move == sIgnoreMoldBreakerMoves[i]) + return TRUE; + } + + if (atkAbility == ABILITY_MOLD_BREAKER + || atkAbility == ABILITY_TERAVOLT + || atkAbility == ABILITY_TURBOBLAZE) + return TRUE; + + return FALSE; +} + +bool32 AI_WeatherHasEffect(void) +{ + if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_AWARE)) + return FALSE; // AI doesn't understand ability suppression concept + + return WEATHER_HAS_EFFECT; +} + +bool32 IsAromaVeilProtectedMove(u16 move) +{ + u32 i; + + 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(u16 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(u16 moveEffect) +{ + switch (moveEffect) + { + case EFFECT_CONFUSE_HIT: + case EFFECT_SWAGGER: + case EFFECT_FLATTER: + case EFFECT_TEETER_DANCE: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsStatLoweringMoveEffect(u16 moveEffect) +{ + switch (moveEffect) + { + 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: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsHazardMoveEffect(u16 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(u16 move, u16 atkAbility) +{ + if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_AWARE)) + return FALSE; + + if (move == MOVE_SKY_DROP + || move == MOVE_SNIPE_SHOT + || atkAbility == ABILITY_PROPELLER_TAIL + || atkAbility == ABILITY_STALWART) + return TRUE; + return FALSE; +} + +// differs from GetTotalAccuracy in that we need to check AI history for item, ability, etc +u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move) +{ + u32 calc, moveAcc, atkParam, defParam; + s8 buff, accStage, evasionStage; + + gPotentialItemEffectBattler = battlerDef; + accStage = gBattleMons[battlerAtk].statStages[STAT_ACC]; + evasionStage = gBattleMons[battlerDef].statStages[STAT_EVASION]; + if (atkAbility == ABILITY_UNAWARE) + evasionStage = DEFAULT_STAT_STAGE; + if (gBattleMoves[move].flags & FLAG_STAT_STAGES_IGNORED) + evasionStage = DEFAULT_STAT_STAGE; + if (defAbility == ABILITY_UNAWARE) + accStage = DEFAULT_STAT_STAGE; + + if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT || gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED) + buff = accStage; + else + buff = accStage + DEFAULT_STAT_STAGE - evasionStage; + + if (buff < MIN_STAT_STAGE) + buff = MIN_STAT_STAGE; + if (buff > MAX_STAT_STAGE) + buff = MAX_STAT_STAGE; + + moveAcc = gBattleMoves[move].accuracy; + // Check Thunder and Hurricane on sunny weather. + if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY + && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) + moveAcc = 50; + // Check Wonder Skin. + if (defAbility == ABILITY_WONDER_SKIN && gBattleMoves[move].power == 0) + moveAcc = 50; + + calc = gAccuracyStageRatios[buff].dividend * moveAcc; + calc /= gAccuracyStageRatios[buff].divisor; + + if (atkAbility == ABILITY_COMPOUND_EYES) + calc = (calc * 130) / 100; // 1.3 compound eyes boost + else if (atkAbility == ABILITY_VICTORY_STAR) + calc = (calc * 110) / 100; // 1.1 victory star boost + if (IsBattlerAlive(BATTLE_PARTNER(battlerAtk)) && GetBattlerAbility(BATTLE_PARTNER(battlerAtk)) == ABILITY_VICTORY_STAR) + calc = (calc * 110) / 100; // 1.1 ally's victory star boost + + if (defAbility == ABILITY_SAND_VEIL && WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SANDSTORM_ANY) + calc = (calc * 80) / 100; // 1.2 sand veil loss + else if (defAbility == ABILITY_SNOW_CLOAK && WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_HAIL_ANY) + calc = (calc * 80) / 100; // 1.2 snow cloak loss + else if (defAbility == ABILITY_TANGLED_FEET && gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + calc = (calc * 50) / 100; // 1.5 tangled feet loss + + if (atkAbility == ABILITY_HUSTLE && IS_MOVE_PHYSICAL(move)) + calc = (calc * 80) / 100; // 1.2 hustle loss + + if (defHoldEffect == HOLD_EFFECT_EVASION_UP) + calc = (calc * (100 - defParam)) / 100; + + if (atkHoldEffect == HOLD_EFFECT_WIDE_LENS) + calc = (calc * (100 + atkParam)) / 100; + else if (atkHoldEffect == HOLD_EFFECT_ZOOM_LENS && GetBattlerTurnOrderNum(battlerAtk) > GetBattlerTurnOrderNum(battlerDef)); + calc = (calc * (100 + atkParam)) / 100; + + return calc; +} + +bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) +{ + // never hits + if (gStatuses3[battlerDef] & (STATUS3_SEMI_INVULNERABLE)) + return FALSE; + + if ((gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) + || (!TestMoveFlags(move, FLAG_HIT_IN_AIR) && gStatuses3[battlerDef] & STATUS3_ON_AIR) + || (!TestMoveFlags(move, FLAG_DMG_UNDERGROUND) && gStatuses3[battlerDef] & STATUS3_UNDERGROUND) + || (!TestMoveFlags(move, FLAG_DMG_UNDERWATER) && gStatuses3[battlerDef] & STATUS3_UNDERWATER)) + return FALSE; + + //TODO - anticipate protect move? + + // always hits + if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS || gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk) + return TRUE; + + if (AI_GetAbility(battlerDef) == ABILITY_NO_GUARD || AI_GetAbility(battlerAtk) == ABILITY_NO_GUARD) + return TRUE; + + if (B_TOXIC_NEVER_MISS >= GEN_6 && gBattleMoves[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON)) + return TRUE; + + // discouraged from hitting + if (AI_WeatherHasEffect() && (gBattleWeather & WEATHER_SUN_ANY) + && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) + return FALSE; + + // increased accuracy but don't always hit + if ((AI_WeatherHasEffect() && + (((gBattleWeather & WEATHER_RAIN_ANY) && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) + || (((gBattleWeather & WEATHER_HAIL_ANY) && move == MOVE_BLIZZARD)))) + || (gBattleMoves[move].effect == EFFECT_VITAL_THROW) + || (gBattleMoves[move].accuracy == 0) + || ((B_MINIMIZE_DMG_ACC >= GEN_6) && (gStatuses3[battlerDef] & STATUS3_MINIMIZED) && (gBattleMoves[move].flags & FLAG_DMG_MINIMIZE))) + { + return TRUE; + } + + return FALSE; +} + +bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move) +{ + u32 holdEffect = AI_GetHoldEffect(battlerDef); + + gPotentialItemEffectBattler = battlerDef; + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < GetBattlerHoldEffectParam(battlerDef)) + return FALSE; //probabilistically speaking, focus band should activate so dont OHKO + else if (holdEffect == HOLD_EFFECT_FOCUS_SASH && GetHealthPercentage(battlerDef) == 100) + 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 + { + u16 odds = accuracy + (gBattleMons[battlerAtk].level - gBattleMons[battlerDef].level); + if (Random() % 100 + 1 < odds && gBattleMons[battlerAtk].level >= gBattleMons[battlerDef].level) + return TRUE; + } + return FALSE; +} + +// stat stages +bool32 BattlerStatCanFall(u8 battler, u16 battlerAbility, u8 stat) +{ + if ((gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) + || (battlerAbility == ABILITY_CONTRARY && gBattleMons[battler].statStages[stat] < MAX_STAT_STAGE)) + return TRUE; + return FALSE; +} + +bool32 BattlerStatCanRise(u8 battler, u16 battlerAbility, u8 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(u8 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(u8 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(u8 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(u8 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; +} + +// checks for growth, gear up, work up +bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability) +{ + if (((!BattlerStatCanRise(battlerId, ability, STAT_ATK)|| !HasMoveWithSplit(battlerId, SPLIT_PHYSICAL)) + && (!BattlerStatCanRise(battlerId, ability, STAT_SPATK) || !HasMoveWithSplit(battlerId, SPLIT_SPECIAL))) + || ability == ABILITY_CONTRARY) + { + return FALSE; + } + return TRUE; +} + +bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index) +{ + s32 dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][index]; + + if (gBattleMons[battlerDef].hp <= dmg) + return TRUE; + return FALSE; +} + +s32 CountUsablePartyMons(u8 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(GetBattlerPosition(battlerId) ^ BIT_FLANK)]; + } + 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_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG) + { + ret++; + } + } + + return ret; +} + +u16 *GetMovesArray(u32 battler) +{ + if (IsBattlerAIControlled(battler) || IsBattlerAIControlled(BATTLE_PARTNER(battler))) + return gBattleMons[battler].moves; + else + return gBattleResources->battleHistory->usedMoves[battler]; +} + +bool32 HasMoveWithSplit(u32 battler, u32 split) +{ + u32 i; + u16 *moves = GetMovesArray(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && GetBattleMoveSplit(moves[i]) == split) + return TRUE; + } + + return FALSE; +} + +bool32 HasMoveWithType(u32 battler, u8 type) +{ + s32 i; + u16 *moves = GetMovesArray(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && gBattleMoves[moves[i]].type == type) + return TRUE; + } + + return FALSE; +} + +bool32 IsInstructBannedMove(u16 move) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sInstructBannedMoves); i++) + { + if (move == sInstructBannedMoves[i]) + return TRUE; + } + return FALSE; +} + +bool32 MoveRequiresRecharging(u16 move) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sRechargeMoves); i++) + { + if (move == sRechargeMoves[i]) + return TRUE; + } + return FALSE; +} + +bool32 MoveCallsOtherMove(u16 move) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sOtherMoveCallingMoves); i++) + { + if (move == sOtherMoveCallingMoves[i]) + return TRUE; + } + return FALSE; +} + +bool32 TestMoveFlagsInMoveset(u8 battler, u32 flags) +{ + s32 i; + u16 *moves = GetMovesArray(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && TestMoveFlags(moves[i], flags)) + return TRUE; + } + return FALSE; +} + +bool32 BattlerHasDamagingMove(u8 battlerId) +{ + u32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && gBattleMoves[moves[i]].power != 0) + return TRUE; + } + + return FALSE; +} + +static u32 GetLeechSeedDamage(u8 battlerId) +{ + u32 damage = 0; + if ((gStatuses3[battlerId] & STATUS3_LEECHSEED) + && gBattleMons[gStatuses3[battlerId] & STATUS3_LEECHSEED_BATTLER].hp != 0) + { + damage = gBattleMons[battlerId].maxHP / 8; + if (damage == 0) + damage = 1; + } + return damage; +} + +static u32 GetNightmareDamage(u8 battlerId) +{ + u32 damage = 0; + if ((gBattleMons[battlerId].status2 & STATUS2_NIGHTMARE) && gBattleMons[battlerId].status1 & STATUS1_SLEEP) + { + damage = gBattleMons[battlerId].maxHP / 4; + if (damage == 0) + damage = 1; + } + return damage; +} + +static u32 GetCurseDamage(u8 battlerId) +{ + u32 damage = 0; + if (gBattleMons[battlerId].status2 & STATUS2_CURSED) + { + damage = gBattleMons[battlerId].maxHP / 4; + if (damage == 0) + damage = 1; + } + return damage; +} + +static u32 GetTrapDamage(u8 battlerId) +{ + // ai has no knowledge about turns remaining + u32 damage = 0; + u32 holdEffect = AI_GetHoldEffect(gBattleStruct->wrappedBy[battlerId]); + if (gBattleMons[battlerId].status2 & STATUS2_WRAPPED) + { + if (holdEffect == HOLD_EFFECT_BINDING_BAND) + damage = gBattleMons[battlerId].maxHP / (B_BINDING_DAMAGE >= GEN_6) ? 6 : 8; + else + damage = gBattleMons[battlerId].maxHP / (B_BINDING_DAMAGE >= GEN_6) ? 8 : 16; + + if (damage == 0) + damage = 1; + } + return damage; +} + +static u32 GetPoisonDamage(u8 battlerId) +{ + u32 damage = 0; + + if (AI_GetAbility(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(u8 battlerId, u16 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(u8 battlerId, u16 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(u8 battlerId) +{ + u32 ability = AI_GetAbility(battlerId); + u32 holdEffect = AI_GetHoldEffect(battlerId); + u32 damage = 0; + if (!AI_WeatherHasEffect()) + return 0; + + if (gBattleWeather & WEATHER_SANDSTORM_ANY) + { + if (BattlerAffectedBySandstorm(battlerId, ability) + && !(gStatuses3[battlerId] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + && holdEffect != HOLD_EFFECT_SAFETY_GOOGLES) + { + damage = gBattleMons[battlerId].maxHP / 16; + if (damage == 0) + damage = 1; + } + } + if ((gBattleWeather & WEATHER_HAIL_ANY) && ability != ABILITY_ICE_BODY) + { + if (BattlerAffectedByHail(battlerId, ability) + && !(gStatuses3[battlerId] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + && holdEffect != HOLD_EFFECT_SAFETY_GOOGLES) + { + damage = gBattleMons[battlerId].maxHP / 16; + if (damage == 0) + damage = 1; + } + } + return damage; +} + +bool32 BattlerHasSecondaryDamage(u8 battlerId) +{ + u32 secondaryDamage; + + if (AI_GetAbility(battlerId) == ABILITY_MAGIC_GUARD) + return FALSE; + + secondaryDamage = GetLeechSeedDamage(battlerId) + + GetNightmareDamage(battlerId) + + GetCurseDamage(battlerId) + + GetTrapDamage(battlerId) + + GetPoisonDamage(battlerId) + + GetWeatherDamage(battlerId); + + if (secondaryDamage != 0) + return TRUE; + return FALSE; +} + +bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability) +{ + if ((BattlerAffectedBySandstorm(battler, ability) || BattlerAffectedByHail(battler, ability)) + && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 16) + return TRUE; + + return FALSE; +} + +// status checks +bool32 AI_ShouldPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +{ + if (defAbility == ABILITY_INSOMNIA + || defAbility == ABILITY_VITAL_SPIRIT + || gBattleMons[battlerDef].status1 & STATUS1_ANY + || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD + || IsAbilityStatusProtected(battlerDef) + || 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; +} + +bool32 AI_ShouldPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +{ + if (defAbility == ABILITY_IMMUNITY + || defAbility == ABILITY_PASTEL_VEIL + || gBattleMons[battlerDef].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battlerDef) + || 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_GetAbility(BATTLE_PARTNER(battlerDef)) == ABILITY_PASTEL_VEIL) + return FALSE; + + return TRUE; +} + +bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +{ + if (defAbility == ABILITY_LIMBER + || IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC) + || gBattleMons[battlerDef].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battlerDef) + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) + return FALSE; + return TRUE; +} + +bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) +{ + if ((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && defAbility == ABILITY_OWN_TEMPO) + || (IsBattlerGrounded(battlerDef) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + { + return FALSE; + } + + return TRUE; +} + +bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) +{ + if (defAbility == ABILITY_WATER_VEIL + || defAbility == ABILITY_WATER_BUBBLE + || IS_BATTLER_OF_TYPE(battlerDef, TYPE_FIRE) + || gBattleMons[battlerDef].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battlerDef) + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove)) + { + return FALSE; + } + return TRUE; +} + +bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGender, u8 defGender) +{ + if (IsBattlerAlive(battlerDef) + && !(gBattleMons[battlerDef].status2 & STATUS2_INFATUATION) + && defAbility != ABILITY_OBLIVIOUS + && atkGender != defGender + && atkGender != MON_GENDERLESS + && defGender != MON_GENDERLESS + && !IsAbilityOnSide(battlerDef, ABILITY_AROMA_VEIL)) + return FALSE; + return TRUE; +} + + +bool32 AnyPartyMemberStatused(u8 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; +} + +bool32 IsPartyFullyHealedExceptBattler(u8 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_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG + && GetMonData(&party[i], MON_DATA_HP) < GetMonData(&party[i], MON_DATA_MAX_HP)) + return FALSE; + } + return TRUE; +} + +u16 GetBattlerSideSpeedAverage(u8 battler) +{ + u16 speed1 = 0; + u16 speed2 = 0; + u8 numBattlersAlive = 0; + + if (IsBattlerAlive(battler)) + { + speed1 = GetBattlerTotalSpeedStat(battler); + numBattlersAlive++; + } + + if (IsDoubleBattle() && IsBattlerAlive(BATTLE_PARTNER(battler))) + { + speed2 = GetBattlerTotalSpeedStat(BATTLE_PARTNER(battler)); + numBattlersAlive++; + } + + return (speed1 + speed2) / numBattlersAlive; +} + +bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex) +{ + if (recoilDmg >= gBattleMons[battlerAtk].hp //Recoil kills attacker + && CountUsablePartyMons(battlerDef) > 1) //Foe has more than 1 target left + { + if (recoilDmg >= gBattleMons[battlerDef].hp && !CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex)) + 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; +} + +// Partner Logic +bool32 IsValidDoubleBattle(u8 battlerAtk) +{ + if (IsDoubleBattle() + && ((IsBattlerAlive(BATTLE_OPPOSITE(battlerAtk)) && IsBattlerAlive(BATTLE_PARTNER(BATTLE_OPPOSITE(battlerAtk)))) || IsBattlerAlive(BATTLE_PARTNER(battlerAtk)))) + return TRUE; + return FALSE; +} + +u16 GetAllyChosenMove(void) +{ + u8 partnerBattler = BATTLE_PARTNER(sBattler_AI); + + if (!IsBattlerAlive(partnerBattler) || !IsBattlerAIControlled(partnerBattler)) + return MOVE_NONE; // TODO: prediction? + else if (partnerBattler > sBattler_AI) // Battler with the lower id chooses the move first. + return MOVE_NONE; + else + return gBattleMons[partnerBattler].moves[gBattleStruct->chosenMovePositions[partnerBattler]]; +} + +bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef) +{ + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + return FALSE; + + if (battlerDef == BATTLE_PARTNER(battlerAtk)) + return TRUE; + + return FALSE; +} + +//PARTNER_MOVE_EFFECT_IS_SAME +bool32 DoesPartnerHaveSameMoveEffect(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (gBattleMoves[move].effect == gBattleMoves[partnerMove].effect + && gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE + && gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef) + { + return TRUE; + } + return FALSE; +} + +//PARTNER_MOVE_EFFECT_IS_SAME_NO_TARGET +bool32 PartnerHasSameMoveEffectWithoutTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (gBattleMoves[move].effect == gBattleMoves[partnerMove].effect + && gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE) + return TRUE; + return FALSE; +} + +//PARTNER_MOVE_EFFECT_IS_STATUS_SAME_TARGET +bool32 PartnerMoveEffectIsStatusSameTarget(u8 battlerAtkPartner, u8 battlerDef, u16 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE + && gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef + && (gBattleMoves[partnerMove].effect == EFFECT_SLEEP + || gBattleMoves[partnerMove].effect == EFFECT_POISON + || gBattleMoves[partnerMove].effect == EFFECT_TOXIC + || gBattleMoves[partnerMove].effect == EFFECT_PARALYZE + || gBattleMoves[partnerMove].effect == EFFECT_WILL_O_WISP + || gBattleMoves[partnerMove].effect == EFFECT_YAWN)) + return TRUE; + return FALSE; +} + +//PARTNER_MOVE_EFFECT_IS_WEATHER +bool32 PartnerMoveEffectIsWeather(u8 battlerAtkPartner, u16 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE + && (gBattleMoves[partnerMove].effect == EFFECT_SUNNY_DAY + || gBattleMoves[partnerMove].effect == EFFECT_RAIN_DANCE + || gBattleMoves[partnerMove].effect == EFFECT_SANDSTORM + || gBattleMoves[partnerMove].effect == EFFECT_HAIL)) + return TRUE; + + return FALSE; +} + +//PARTNER_MOVE_EFFECT_IS_TERRAIN +bool32 PartnerMoveEffectIsTerrain(u8 battlerAtkPartner, u16 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE + && (gBattleMoves[partnerMove].effect == EFFECT_GRASSY_TERRAIN + || gBattleMoves[partnerMove].effect == EFFECT_MISTY_TERRAIN + || gBattleMoves[partnerMove].effect == EFFECT_ELECTRIC_TERRAIN + || gBattleMoves[partnerMove].effect == EFFECT_PSYCHIC_TERRAIN)) + return TRUE; + + return FALSE; +} + +//PARTNER_MOVE_IS_TAILWIND_TRICKROOM +bool32 PartnerMoveIs(u8 battlerAtkPartner, u16 partnerMove, u16 moveCheck) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE && partnerMove == moveCheck) + return TRUE; + return FALSE; +} + +//PARTNER_MOVE_IS_SAME +bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE && move == partnerMove && gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef) + return TRUE; + return FALSE; +} + +//PARTNER_MOVE_IS_SAME_NO_TARGET +bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove) +{ + if (!IsDoubleBattle()) + return FALSE; + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE && move == partnerMove) + return TRUE; + return FALSE; } diff --git a/src/battle_factory.c b/src/battle_factory.c index a2b1d337ac..98af96664c 100644 --- a/src/battle_factory.c +++ b/src/battle_factory.c @@ -850,13 +850,13 @@ u32 GetAiScriptsInBattleFactory(void) int challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7; if (gTrainerBattleOpponent_A == TRAINER_FRONTIER_BRAIN) - return AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY; + return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY; else if (challengeNum < 2) return 0; else if (challengeNum < 4) - return AI_SCRIPT_CHECK_BAD_MOVE; + return AI_FLAG_CHECK_BAD_MOVE; else - return AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY; + return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY; } } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 16e2989f8e..9872d04fe9 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -813,13 +813,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_metalburstdamagecalculator, // 0xFF }; -struct StatFractions -{ - u8 dividend; - u8 divisor; -}; - -static const struct StatFractions sAccuracyStageRatios[] = +const struct StatFractions gAccuracyStageRatios[] = { { 33, 100}, // -6 { 36, 100}, // -5 @@ -1536,8 +1530,8 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move) if (defAbility == ABILITY_WONDER_SKIN && gBattleMoves[move].power == 0) moveAcc = 50; - calc = sAccuracyStageRatios[buff].dividend * moveAcc; - calc /= sAccuracyStageRatios[buff].divisor; + calc = gAccuracyStageRatios[buff].dividend * moveAcc; + calc /= gAccuracyStageRatios[buff].divisor; if (atkAbility == ABILITY_COMPOUND_EYES) calc = (calc * 130) / 100; // 1.3 compound eyes boost @@ -7646,51 +7640,25 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 7; return; case VARIOUS_SET_SIMPLE_BEAM: - switch (gBattleMons[gActiveBattler].ability) + if (IsEntrainmentTargetOrSimpleBeamBannedAbility(gBattleMons[gActiveBattler].ability)) { - case ABILITY_SIMPLE: - case ABILITY_TRUANT: - case ABILITY_STANCE_CHANGE: - case ABILITY_DISGUISE: - case ABILITY_MULTITYPE: gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); - break; - default: + } + else + { gBattleMons[gActiveBattler].ability = ABILITY_SIMPLE; gBattlescriptCurrInstr += 7; break; } return; case VARIOUS_TRY_ENTRAINMENT: - switch (gBattleMons[gBattlerTarget].ability) + if (IsEntrainmentBannedAbilityAttacker(gBattleMons[gBattlerAttacker].ability) + || IsEntrainmentTargetOrSimpleBeamBannedAbility(gBattleMons[gBattlerTarget].ability)) { - case ABILITY_TRUANT: - case ABILITY_MULTITYPE: - case ABILITY_STANCE_CHANGE: - case ABILITY_SCHOOLING: - case ABILITY_COMATOSE: - case ABILITY_SHIELDS_DOWN: - case ABILITY_DISGUISE: - case ABILITY_RKS_SYSTEM: - case ABILITY_BATTLE_BOND: - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); - return; - } - switch (gBattleMons[gBattlerAttacker].ability) - { - case ABILITY_TRACE: - case ABILITY_FORECAST: - case ABILITY_FLOWER_GIFT: - case ABILITY_ZEN_MODE: - case ABILITY_ILLUSION: - case ABILITY_IMPOSTER: - case ABILITY_POWER_OF_ALCHEMY: - case ABILITY_RECEIVER: - case ABILITY_DISGUISE: - case ABILITY_POWER_CONSTRUCT: gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); return; } + if (gBattleMons[gBattlerTarget].ability == gBattleMons[gBattlerAttacker].ability) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); @@ -10945,6 +10913,12 @@ static void Cmd_callterrainattack(void) // nature power gBattlescriptCurrInstr++; } +u16 GetNaturePowerMove(void) +{ + //TODO terrain + return sNaturePowerMoves[gBattleTerrain]; +} + static void Cmd_cureifburnedparalysedorpoisoned(void) // refresh { if (gBattleMons[gBattlerAttacker].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON)) @@ -11111,18 +11085,20 @@ static void Cmd_tryswapitems(void) // trick static void Cmd_trycopyability(void) // role play { - switch (gBattleMons[gBattlerTarget].ability) + u16 defAbility = gBattleMons[gBattlerTarget].ability; + + if (gBattleMons[gBattlerAttacker].ability == defAbility + || defAbility == ABILITY_NONE + || IsRolePlayBannedAbilityAtk(gBattleMons[gBattlerAttacker].ability) + || IsRolePlayBannedAbility(defAbility)) { - case ABILITY_NONE: - case ABILITY_WONDER_GUARD: - case ABILITY_DISGUISE: - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); - break; - default: - gBattleMons[gBattlerAttacker].ability = gBattleMons[gBattlerTarget].ability; - gLastUsedAbility = gBattleMons[gBattlerTarget].ability; - gBattlescriptCurrInstr += 5; - break; + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBattlerAttacker].ability = defAbility; + gLastUsedAbility = defAbility; + gBattlescriptCurrInstr += 5; } } @@ -11176,23 +11152,14 @@ static void Cmd_settoxicspikes(void) static void Cmd_setgastroacid(void) { - switch (gBattleMons[gBattlerTarget].ability) + if (IsGastroAcidBannedAbility(gBattleMons[gBattlerTarget].ability)) { - case ABILITY_MULTITYPE: - case ABILITY_STANCE_CHANGE: - case ABILITY_SCHOOLING: - case ABILITY_COMATOSE: - case ABILITY_SHIELDS_DOWN: - case ABILITY_DISGUISE: - case ABILITY_RKS_SYSTEM: - case ABILITY_BATTLE_BOND: - case ABILITY_POWER_CONSTRUCT: gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); - break; - default: + } + else + { gStatuses3[gBattlerTarget] |= STATUS3_GASTRO_ACID; gBattlescriptCurrInstr += 5; - break; } } @@ -11261,24 +11228,13 @@ static void Cmd_setroom(void) static void Cmd_tryswapabilities(void) // skill swap { - switch (gBattleMons[gBattlerAttacker].ability) + if (IsSkillSwapBannedAbility(gBattleMons[gBattlerAttacker].ability) + || IsSkillSwapBannedAbility(gBattleMons[gBattlerTarget].ability)) { - case ABILITY_NONE: - case ABILITY_WONDER_GUARD: - case ABILITY_DISGUISE: gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); return; } - - switch (gBattleMons[gBattlerTarget].ability) - { - case ABILITY_NONE: - case ABILITY_WONDER_GUARD: - case ABILITY_DISGUISE: - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); - return; - } - + if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); @@ -11751,6 +11707,13 @@ static void Cmd_tryrecycleitem(void) } } +bool32 CanCamouflage(u8 battlerId) +{ + if (IS_BATTLER_OF_TYPE(battlerId, sTerrainToType[gBattleTerrain])) + return FALSE; + return TRUE; +} + static void Cmd_settypetoterrain(void) { if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, sTerrainToType[gBattleTerrain])) @@ -12271,11 +12234,36 @@ static void Cmd_trainerslideout(void) gBattlescriptCurrInstr += 2; } +static const u16 sTelekinesisBanList[] = +{ + SPECIES_DIGLETT, + SPECIES_DUGTRIO, + #ifdef POKEMON_EXPANSION + SPECIES_DIGLETT_ALOLAN, + SPECIES_DUGTRIO_ALOLAN, + SPECIES_SANDYGAST, + SPECIES_PALOSSAND, + SPECIES_GENGAR_MEGA, + #endif +}; + +bool32 IsTelekinesisBannedSpecies(u16 species) +{ + u32 i; + + for (i = 0; i < ARRAY_COUNT(sTelekinesisBanList); i++) + { + if (species == sTelekinesisBanList[i]) + return TRUE; + } + return FALSE; +} + static void Cmd_settelekinesis(void) { if (gStatuses3[gBattlerTarget] & (STATUS3_TELEKINESIS | STATUS3_ROOTED | STATUS3_SMACKED_DOWN) || gFieldStatuses & STATUS_FIELD_GRAVITY - || (gBattleMons[gBattlerTarget].species == SPECIES_DIGLETT || gBattleMons[gBattlerTarget].species == SPECIES_DUGTRIO)) + || IsTelekinesisBannedSpecies(gBattleMons[gBattlerTarget].species)) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); } @@ -12343,19 +12331,14 @@ static void Cmd_trygetbaddreamstarget(void) static void Cmd_tryworryseed(void) { - switch (gBattleMons[gBattlerTarget].ability) + if (IsWorrySeedBannedAbility(gBattleMons[gBattlerTarget].ability)) { - case ABILITY_INSOMNIA: - case ABILITY_MULTITYPE: - case ABILITY_TRUANT: - case ABILITY_STANCE_CHANGE: - case ABILITY_DISGUISE: gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); - break; - default: + } + else + { gBattleMons[gBattlerTarget].ability = ABILITY_INSOMNIA; gBattlescriptCurrInstr += 5; - break; } } diff --git a/src/battle_util.c b/src/battle_util.c index b929b7499d..846e269b13 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -63,6 +63,131 @@ static const u8 sPkblToEscapeFactor[][3] = {{0, 0, 0}, {3, 5, 0}, {2, 3, 0}, {1, static const u8 sGoNearCounterToCatchFactor[] = {4, 3, 2, 1}; static const u8 sGoNearCounterToEscapeFactor[] = {4, 4, 4, 4}; +static const u16 sSkillSwapBannedAbilities[] = +{ + ABILITY_WONDER_GUARD, + ABILITY_MULTITYPE, + ABILITY_ILLUSION, + ABILITY_STANCE_CHANGE, + ABILITY_SCHOOLING, + ABILITY_COMATOSE, + ABILITY_SHIELDS_DOWN, + ABILITY_DISGUISE, + ABILITY_RKS_SYSTEM, + ABILITY_BATTLE_BOND, + ABILITY_POWER_CONSTRUCT, + ABILITY_NEUTRALIZING_GAS, + ABILITY_ICE_FACE, + ABILITY_HUNGER_SWITCH, + ABILITY_GULP_MISSILE, +}; + +static const u16 sRolePlayBannedAbilities[] = +{ + ABILITY_TRACE, + ABILITY_WONDER_GUARD, + ABILITY_FORECAST, + ABILITY_FLOWER_GIFT, + ABILITY_MULTITYPE, + ABILITY_ILLUSION, + ABILITY_ZEN_MODE, + ABILITY_IMPOSTER, + ABILITY_STANCE_CHANGE, + ABILITY_POWER_OF_ALCHEMY, + ABILITY_RECEIVER, + ABILITY_SCHOOLING, + ABILITY_COMATOSE, + ABILITY_SHIELDS_DOWN, + ABILITY_DISGUISE, + ABILITY_RKS_SYSTEM, + ABILITY_BATTLE_BOND, + ABILITY_POWER_CONSTRUCT, + ABILITY_ICE_FACE, + ABILITY_HUNGER_SWITCH, + ABILITY_GULP_MISSILE, +}; + +static const u16 sRolePlayBannedAttackerAbilities[] = +{ + ABILITY_MULTITYPE, + ABILITY_ZEN_MODE, + ABILITY_STANCE_CHANGE, + ABILITY_SCHOOLING, + ABILITY_COMATOSE, + ABILITY_SHIELDS_DOWN, + ABILITY_DISGUISE, + ABILITY_RKS_SYSTEM, + ABILITY_BATTLE_BOND, + ABILITY_POWER_CONSTRUCT, + ABILITY_ICE_FACE, + ABILITY_GULP_MISSILE, +}; + +static const u16 sWorrySeedBannedAbilities[] = +{ + ABILITY_MULTITYPE, + ABILITY_STANCE_CHANGE, + ABILITY_SCHOOLING, + ABILITY_COMATOSE, + ABILITY_SHIELDS_DOWN, + ABILITY_DISGUISE, + ABILITY_RKS_SYSTEM, + ABILITY_BATTLE_BOND, + ABILITY_POWER_CONSTRUCT, + ABILITY_TRUANT, + ABILITY_ICE_FACE, + ABILITY_GULP_MISSILE, +}; + +static const u16 sGastroAcidBannedAbilities[] = +{ + ABILITY_MULTITYPE, + ABILITY_STANCE_CHANGE, + ABILITY_SCHOOLING, + ABILITY_COMATOSE, + ABILITY_SHIELDS_DOWN, + ABILITY_DISGUISE, + ABILITY_RKS_SYSTEM, + ABILITY_BATTLE_BOND, + ABILITY_POWER_CONSTRUCT, + ABILITY_ICE_FACE, + ABILITY_GULP_MISSILE, +}; + +static const u16 sEntrainmentBannedAttackerAbilities[] = +{ + ABILITY_TRACE, + ABILITY_FORECAST, + ABILITY_FLOWER_GIFT, + ABILITY_ZEN_MODE, + ABILITY_ILLUSION, + ABILITY_IMPOSTER, + ABILITY_POWER_OF_ALCHEMY, + ABILITY_RECEIVER, + ABILITY_DISGUISE, + ABILITY_POWER_CONSTRUCT, + ABILITY_NEUTRALIZING_GAS, + ABILITY_ICE_FACE, + ABILITY_HUNGER_SWITCH, + ABILITY_GULP_MISSILE, +}; + +static const u16 sEntrainmentTargetSimpleBeamBannedAbilities[] = +{ + ABILITY_TRUANT, + ABILITY_MULTITYPE, + ABILITY_STANCE_CHANGE, + ABILITY_SCHOOLING, + ABILITY_COMATOSE, + ABILITY_SHIELDS_DOWN, + ABILITY_DISGUISE, + ABILITY_RKS_SYSTEM, + ABILITY_BATTLE_BOND, + ABILITY_ICE_FACE, + ABILITY_GULP_MISSILE, +}; + +// Functions void HandleAction_UseMove(void) { u32 i, side, moveType, var = 4; @@ -1325,11 +1450,11 @@ static bool32 IsGravityPreventingMove(u32 move) } } -static bool32 IsHealBlockPreventingMove(u32 battler, u32 move) +bool32 IsHealBlockPreventingMove(u32 battler, u32 move) { if (!(gStatuses3[battler] & STATUS3_HEAL_BLOCK)) return FALSE; - + switch (gBattleMoves[move].effect) { case EFFECT_ABSORB: @@ -5339,10 +5464,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) u8 ppBonuses; u16 move; - if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) - mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]]; - else - mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]]; + mon = GetBattlerPartyData(battlerId); for (i = 0; i < MAX_MON_MOVES; i++) { move = GetMonData(mon, MON_DATA_MOVE1 + i); @@ -7830,3 +7952,123 @@ u8 GetBattleMoveSplit(u32 moveId) else return SPLIT_SPECIAL; } + +bool32 TestMoveFlags(u16 move, u32 flag) +{ + if (gBattleMoves[move].flags & flag) + return TRUE; + return FALSE; +} + +struct Pokemon *GetBattlerPartyData(u8 battlerId) +{ + struct Pokemon *mon; + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) + mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]]; + else + mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]]; + + return mon; +} + +//Make sure the input bank is any bank on the specific mon's side +bool32 CanFling(u8 battlerId) +{ + u16 item = gBattleMons[battlerId].item; + u16 itemEffect = ItemId_GetHoldEffect(item); + + if (item == ITEM_NONE + || GetBattlerAbility(battlerId) == ABILITY_KLUTZ + || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM + || gDisableStructs[battlerId].embargoTimer != 0 + || !CanBattlerGetOrLoseItem(battlerId, item) + //|| itemEffect == HOLD_EFFECT_PRIMAL_ORB + || itemEffect == HOLD_EFFECT_GEMS + #ifdef ITEM_ABILITY_CAPSULE + || item == ITEM_ABILITY_CAPSULE + #endif + || (ItemId_GetPocket(item) == POCKET_BERRIES && IsAbilityOnSide(battlerId, ABILITY_UNNERVE)) + || GetPocketByItemId(item) == POCKET_POKE_BALLS) + return FALSE; + + return TRUE; +} + +// ability checks +bool32 IsRolePlayBannedAbilityAtk(u16 ability) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sRolePlayBannedAttackerAbilities); i++) + { + if (ability == sRolePlayBannedAttackerAbilities[i]) + return TRUE; + } + return FALSE; +} + +bool32 IsRolePlayBannedAbility(u16 ability) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sRolePlayBannedAbilities); i++) + { + if (ability == sRolePlayBannedAbilities[i]) + return TRUE; + } + return FALSE; +} + +bool32 IsSkillSwapBannedAbility(u16 ability) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sSkillSwapBannedAbilities); i++) + { + if (ability == sSkillSwapBannedAbilities[i]) + return TRUE; + } + return FALSE; +} + +bool32 IsWorrySeedBannedAbility(u16 ability) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sWorrySeedBannedAbilities); i++) + { + if (ability == sWorrySeedBannedAbilities[i]) + return TRUE; + } + return FALSE; +} + +bool32 IsGastroAcidBannedAbility(u16 ability) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sGastroAcidBannedAbilities); i++) + { + if (ability == sGastroAcidBannedAbilities[i]) + return TRUE; + } + return FALSE; +} + +bool32 IsEntrainmentBannedAbilityAttacker(u16 ability) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sEntrainmentBannedAttackerAbilities); i++) + { + if (ability == sEntrainmentBannedAttackerAbilities[i]) + return TRUE; + } + return FALSE; +} + +bool32 IsEntrainmentTargetOrSimpleBeamBannedAbility(u16 ability) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sEntrainmentTargetSimpleBeamBannedAbilities); i++) + { + if (ability == sEntrainmentTargetSimpleBeamBannedAbilities[i]) + return TRUE; + } + return FALSE; +} + diff --git a/src/data/trainers.h b/src/data/trainers.h index 163a8296db..619763ea11 100644 --- a/src/data/trainers.h +++ b/src/data/trainers.h @@ -22,7 +22,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer1), .party = {.NoItemDefaultMoves = sParty_Sawyer1}, }, @@ -36,7 +36,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntAquaHideout1), .party = {.NoItemDefaultMoves = sParty_GruntAquaHideout1}, }, @@ -50,7 +50,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntAquaHideout2), .party = {.NoItemDefaultMoves = sParty_GruntAquaHideout2}, }, @@ -64,7 +64,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntAquaHideout3), .party = {.NoItemDefaultMoves = sParty_GruntAquaHideout3}, }, @@ -78,7 +78,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntAquaHideout4), .party = {.NoItemDefaultMoves = sParty_GruntAquaHideout4}, }, @@ -92,7 +92,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSeafloorCavern1), .party = {.NoItemDefaultMoves = sParty_GruntSeafloorCavern1}, }, @@ -106,7 +106,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSeafloorCavern2), .party = {.NoItemDefaultMoves = sParty_GruntSeafloorCavern2}, }, @@ -120,7 +120,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSeafloorCavern3), .party = {.NoItemDefaultMoves = sParty_GruntSeafloorCavern3}, }, @@ -134,7 +134,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABRIELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Gabrielle1), .party = {.NoItemDefaultMoves = sParty_Gabrielle1}, }, @@ -148,7 +148,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntPetalburgWoods), .party = {.NoItemDefaultMoves = sParty_GruntPetalburgWoods}, }, @@ -162,7 +162,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARCEL"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Marcel), .party = {.NoItemDefaultMoves = sParty_Marcel}, }, @@ -176,7 +176,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALBERTO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Alberto), .party = {.NoItemDefaultMoves = sParty_Alberto}, }, @@ -190,7 +190,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ed), .party = {.NoItemDefaultMoves = sParty_Ed}, }, @@ -204,7 +204,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSeafloorCavern4), .party = {.NoItemDefaultMoves = sParty_GruntSeafloorCavern4}, }, @@ -218,7 +218,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DECLAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Declan), .party = {.NoItemDefaultMoves = sParty_Declan}, }, @@ -232,7 +232,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntRusturfTunnel), .party = {.NoItemDefaultMoves = sParty_GruntRusturfTunnel}, }, @@ -246,7 +246,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntWeatherInst1), .party = {.NoItemDefaultMoves = sParty_GruntWeatherInst1}, }, @@ -260,7 +260,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntWeatherInst2), .party = {.NoItemDefaultMoves = sParty_GruntWeatherInst2}, }, @@ -274,7 +274,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntWeatherInst3), .party = {.NoItemDefaultMoves = sParty_GruntWeatherInst3}, }, @@ -288,7 +288,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMuseum1), .party = {.NoItemDefaultMoves = sParty_GruntMuseum1}, }, @@ -302,7 +302,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMuseum2), .party = {.NoItemDefaultMoves = sParty_GruntMuseum2}, }, @@ -316,7 +316,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSpaceCenter1), .party = {.NoItemDefaultMoves = sParty_GruntSpaceCenter1}, }, @@ -330,7 +330,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMtPyre1), .party = {.NoItemDefaultMoves = sParty_GruntMtPyre1}, }, @@ -344,7 +344,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMtPyre2), .party = {.NoItemDefaultMoves = sParty_GruntMtPyre2}, }, @@ -358,7 +358,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMtPyre3), .party = {.NoItemDefaultMoves = sParty_GruntMtPyre3}, }, @@ -372,7 +372,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntWeatherInst4), .party = {.NoItemDefaultMoves = sParty_GruntWeatherInst4}, }, @@ -386,7 +386,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntAquaHideout5), .party = {.NoItemDefaultMoves = sParty_GruntAquaHideout5}, }, @@ -400,7 +400,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntAquaHideout6), .party = {.NoItemDefaultMoves = sParty_GruntAquaHideout6}, }, @@ -414,7 +414,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FREDRICK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Fredrick), .party = {.NoItemDefaultMoves = sParty_Fredrick}, }, @@ -428,7 +428,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MATT"), .items = {ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Matt), .party = {.NoItemDefaultMoves = sParty_Matt}, }, @@ -442,7 +442,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ZANDER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Zander), .party = {.NoItemDefaultMoves = sParty_Zander}, }, @@ -456,7 +456,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_ShellyWeatherInstitute), .party = {.NoItemDefaultMoves = sParty_ShellyWeatherInstitute}, }, @@ -470,7 +470,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_ShellySeafloorCavern), .party = {.NoItemDefaultMoves = sParty_ShellySeafloorCavern}, }, @@ -484,7 +484,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ARCHIE"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Archie), .party = {.NoItemDefaultMoves = sParty_Archie}, }, @@ -498,7 +498,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Leah), .party = {.NoItemDefaultMoves = sParty_Leah}, }, @@ -512,7 +512,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAISY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Daisy), .party = {.NoItemDefaultMoves = sParty_Daisy}, }, @@ -526,7 +526,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROSE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Rose1), .party = {.NoItemDefaultMoves = sParty_Rose1}, }, @@ -540,7 +540,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FELIX"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Felix), .party = {.NoItemCustomMoves = sParty_Felix}, }, @@ -554,7 +554,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VIOLET"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Violet), .party = {.NoItemDefaultMoves = sParty_Violet}, }, @@ -568,7 +568,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROSE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Rose2), .party = {.NoItemDefaultMoves = sParty_Rose2}, }, @@ -582,7 +582,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROSE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Rose3), .party = {.NoItemDefaultMoves = sParty_Rose3}, }, @@ -596,7 +596,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROSE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Rose4), .party = {.NoItemDefaultMoves = sParty_Rose4}, }, @@ -610,7 +610,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROSE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Rose5), .party = {.NoItemDefaultMoves = sParty_Rose5}, }, @@ -624,7 +624,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUSTY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dusty1), .party = {.NoItemCustomMoves = sParty_Dusty1}, }, @@ -638,7 +638,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHIP"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Chip), .party = {.NoItemCustomMoves = sParty_Chip}, }, @@ -652,7 +652,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FOSTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Foster), .party = {.NoItemCustomMoves = sParty_Foster}, }, @@ -666,7 +666,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUSTY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dusty2), .party = {.NoItemCustomMoves = sParty_Dusty2}, }, @@ -680,7 +680,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUSTY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dusty3), .party = {.NoItemCustomMoves = sParty_Dusty3}, }, @@ -694,7 +694,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUSTY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dusty4), .party = {.NoItemCustomMoves = sParty_Dusty4}, }, @@ -708,7 +708,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUSTY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dusty5), .party = {.NoItemCustomMoves = sParty_Dusty5}, }, @@ -722,7 +722,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABBY & TY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GabbyAndTy1), .party = {.NoItemDefaultMoves = sParty_GabbyAndTy1}, }, @@ -736,7 +736,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABBY & TY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GabbyAndTy2), .party = {.NoItemDefaultMoves = sParty_GabbyAndTy2}, }, @@ -750,7 +750,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABBY & TY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GabbyAndTy3), .party = {.NoItemDefaultMoves = sParty_GabbyAndTy3}, }, @@ -764,7 +764,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABBY & TY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GabbyAndTy4), .party = {.NoItemDefaultMoves = sParty_GabbyAndTy4}, }, @@ -778,7 +778,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABBY & TY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GabbyAndTy5), .party = {.NoItemDefaultMoves = sParty_GabbyAndTy5}, }, @@ -792,7 +792,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABBY & TY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GabbyAndTy6), .party = {.NoItemCustomMoves = sParty_GabbyAndTy6}, }, @@ -806,7 +806,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LOLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lola1), .party = {.NoItemDefaultMoves = sParty_Lola1}, }, @@ -820,7 +820,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AUSTINA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Austina), .party = {.NoItemDefaultMoves = sParty_Austina}, }, @@ -834,7 +834,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GWEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Gwen), .party = {.NoItemDefaultMoves = sParty_Gwen}, }, @@ -848,7 +848,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LOLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lola2), .party = {.NoItemDefaultMoves = sParty_Lola2}, }, @@ -862,7 +862,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LOLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lola3), .party = {.NoItemDefaultMoves = sParty_Lola3}, }, @@ -876,7 +876,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LOLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lola4), .party = {.NoItemDefaultMoves = sParty_Lola4}, }, @@ -890,7 +890,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LOLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lola5), .party = {.NoItemDefaultMoves = sParty_Lola5}, }, @@ -904,7 +904,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ricky1), .party = {.NoItemCustomMoves = sParty_Ricky1}, }, @@ -918,7 +918,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SIMON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Simon), .party = {.NoItemDefaultMoves = sParty_Simon}, }, @@ -932,7 +932,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHARLIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Charlie), .party = {.NoItemDefaultMoves = sParty_Charlie}, }, @@ -946,7 +946,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ricky2), .party = {.NoItemCustomMoves = sParty_Ricky2}, }, @@ -960,7 +960,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ricky3), .party = {.NoItemCustomMoves = sParty_Ricky3}, }, @@ -974,7 +974,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ricky4), .party = {.NoItemCustomMoves = sParty_Ricky4}, }, @@ -988,7 +988,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ricky5), .party = {.NoItemCustomMoves = sParty_Ricky5}, }, @@ -1002,7 +1002,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RANDALL"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Randall), .party = {.ItemCustomMoves = sParty_Randall}, }, @@ -1016,7 +1016,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PARKER"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Parker), .party = {.ItemCustomMoves = sParty_Parker}, }, @@ -1030,7 +1030,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GEORGE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_George), .party = {.ItemCustomMoves = sParty_George}, }, @@ -1044,7 +1044,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERKE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Berke), .party = {.ItemCustomMoves = sParty_Berke}, }, @@ -1058,7 +1058,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAXTON"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Braxton), .party = {.NoItemCustomMoves = sParty_Braxton}, }, @@ -1072,7 +1072,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VINCENT"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Vincent), .party = {.NoItemDefaultMoves = sParty_Vincent}, }, @@ -1086,7 +1086,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEROY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Leroy), .party = {.NoItemDefaultMoves = sParty_Leroy}, }, @@ -1100,7 +1100,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton1), .party = {.NoItemDefaultMoves = sParty_Wilton1}, }, @@ -1114,7 +1114,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDGAR"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Edgar), .party = {.NoItemDefaultMoves = sParty_Edgar}, }, @@ -1128,7 +1128,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALBERT"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Albert), .party = {.NoItemDefaultMoves = sParty_Albert}, }, @@ -1142,7 +1142,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAMUEL"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Samuel), .party = {.NoItemDefaultMoves = sParty_Samuel}, }, @@ -1156,7 +1156,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VITO"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Vito), .party = {.NoItemDefaultMoves = sParty_Vito}, }, @@ -1170,7 +1170,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("OWEN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Owen), .party = {.NoItemDefaultMoves = sParty_Owen}, }, @@ -1184,7 +1184,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton2), .party = {.NoItemDefaultMoves = sParty_Wilton2}, }, @@ -1198,7 +1198,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton3), .party = {.NoItemDefaultMoves = sParty_Wilton3}, }, @@ -1212,7 +1212,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton4), .party = {.NoItemDefaultMoves = sParty_Wilton4}, }, @@ -1226,7 +1226,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton5), .party = {.NoItemDefaultMoves = sParty_Wilton5}, }, @@ -1240,7 +1240,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WARREN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Warren), .party = {.NoItemDefaultMoves = sParty_Warren}, }, @@ -1254,7 +1254,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Mary), .party = {.ItemCustomMoves = sParty_Mary}, }, @@ -1268,7 +1268,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEXIA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Alexia), .party = {.ItemCustomMoves = sParty_Alexia}, }, @@ -1282,7 +1282,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JODY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Jody), .party = {.ItemCustomMoves = sParty_Jody}, }, @@ -1296,7 +1296,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WENDY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Wendy), .party = {.NoItemCustomMoves = sParty_Wendy}, }, @@ -1310,7 +1310,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KEIRA"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Keira), .party = {.NoItemDefaultMoves = sParty_Keira}, }, @@ -1324,7 +1324,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke1), .party = {.NoItemDefaultMoves = sParty_Brooke1}, }, @@ -1338,7 +1338,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNIFER"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jennifer), .party = {.NoItemDefaultMoves = sParty_Jennifer}, }, @@ -1352,7 +1352,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HOPE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Hope), .party = {.NoItemDefaultMoves = sParty_Hope}, }, @@ -1366,7 +1366,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHANNON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shannon), .party = {.NoItemDefaultMoves = sParty_Shannon}, }, @@ -1380,7 +1380,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MICHELLE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Michelle), .party = {.NoItemDefaultMoves = sParty_Michelle}, }, @@ -1394,7 +1394,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAROLINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Caroline), .party = {.NoItemDefaultMoves = sParty_Caroline}, }, @@ -1408,7 +1408,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JULIE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Julie), .party = {.NoItemDefaultMoves = sParty_Julie}, }, @@ -1422,7 +1422,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke2), .party = {.NoItemDefaultMoves = sParty_Brooke2}, }, @@ -1436,7 +1436,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke3), .party = {.NoItemDefaultMoves = sParty_Brooke3}, }, @@ -1450,7 +1450,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke4), .party = {.NoItemDefaultMoves = sParty_Brooke4}, }, @@ -1464,7 +1464,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke5), .party = {.NoItemDefaultMoves = sParty_Brooke5}, }, @@ -1478,7 +1478,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PATRICIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Patricia), .party = {.NoItemDefaultMoves = sParty_Patricia}, }, @@ -1492,7 +1492,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KINDRA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kindra), .party = {.NoItemDefaultMoves = sParty_Kindra}, }, @@ -1506,7 +1506,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TAMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tammy), .party = {.NoItemDefaultMoves = sParty_Tammy}, }, @@ -1520,7 +1520,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VALERIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Valerie1), .party = {.NoItemDefaultMoves = sParty_Valerie1}, }, @@ -1534,7 +1534,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TASHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tasha), .party = {.NoItemDefaultMoves = sParty_Tasha}, }, @@ -1548,7 +1548,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VALERIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Valerie2), .party = {.NoItemDefaultMoves = sParty_Valerie2}, }, @@ -1562,7 +1562,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VALERIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Valerie3), .party = {.NoItemDefaultMoves = sParty_Valerie3}, }, @@ -1576,7 +1576,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VALERIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Valerie4), .party = {.NoItemDefaultMoves = sParty_Valerie4}, }, @@ -1590,7 +1590,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VALERIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Valerie5), .party = {.NoItemDefaultMoves = sParty_Valerie5}, }, @@ -1604,7 +1604,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CINDY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cindy1), .party = {.ItemDefaultMoves = sParty_Cindy1}, }, @@ -1618,7 +1618,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAPHNE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Daphne), .party = {.ItemCustomMoves = sParty_Daphne}, }, @@ -1632,7 +1632,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSpaceCenter2), .party = {.NoItemDefaultMoves = sParty_GruntSpaceCenter2}, }, @@ -1646,7 +1646,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CINDY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cindy2), .party = {.ItemCustomMoves = sParty_Cindy2}, }, @@ -1660,7 +1660,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRIANNA"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Brianna), .party = {.ItemDefaultMoves = sParty_Brianna}, }, @@ -1674,7 +1674,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NAOMI"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Naomi), .party = {.ItemDefaultMoves = sParty_Naomi}, }, @@ -1688,7 +1688,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CINDY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cindy3), .party = {.ItemDefaultMoves = sParty_Cindy3}, }, @@ -1702,7 +1702,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CINDY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cindy4), .party = {.ItemDefaultMoves = sParty_Cindy4}, }, @@ -1716,7 +1716,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CINDY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cindy5), .party = {.ItemDefaultMoves = sParty_Cindy5}, }, @@ -1730,7 +1730,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CINDY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cindy6), .party = {.ItemCustomMoves = sParty_Cindy6}, }, @@ -1744,7 +1744,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MELISSA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Melissa), .party = {.NoItemDefaultMoves = sParty_Melissa}, }, @@ -1758,7 +1758,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHEILA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Sheila), .party = {.NoItemDefaultMoves = sParty_Sheila}, }, @@ -1772,7 +1772,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHIRLEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Shirley), .party = {.NoItemDefaultMoves = sParty_Shirley}, }, @@ -1786,7 +1786,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JESSICA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jessica1), .party = {.NoItemCustomMoves = sParty_Jessica1}, }, @@ -1800,7 +1800,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CONNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Connie), .party = {.NoItemDefaultMoves = sParty_Connie}, }, @@ -1814,7 +1814,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRIDGET"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bridget), .party = {.NoItemDefaultMoves = sParty_Bridget}, }, @@ -1828,7 +1828,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("OLIVIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Olivia), .party = {.NoItemCustomMoves = sParty_Olivia}, }, @@ -1842,7 +1842,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIFFANY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tiffany), .party = {.NoItemDefaultMoves = sParty_Tiffany}, }, @@ -1856,7 +1856,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JESSICA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jessica2), .party = {.NoItemCustomMoves = sParty_Jessica2}, }, @@ -1870,7 +1870,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JESSICA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jessica3), .party = {.NoItemCustomMoves = sParty_Jessica3}, }, @@ -1884,7 +1884,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JESSICA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jessica4), .party = {.NoItemCustomMoves = sParty_Jessica4}, }, @@ -1898,7 +1898,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JESSICA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jessica5), .party = {.NoItemCustomMoves = sParty_Jessica5}, }, @@ -1912,7 +1912,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINSTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Winston1), .party = {.ItemDefaultMoves = sParty_Winston1}, }, @@ -1926,7 +1926,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MOLLIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Mollie), .party = {.NoItemDefaultMoves = sParty_Mollie}, }, @@ -1940,7 +1940,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GARRET"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Garret), .party = {.ItemDefaultMoves = sParty_Garret}, }, @@ -1954,7 +1954,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINSTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Winston2), .party = {.ItemDefaultMoves = sParty_Winston2}, }, @@ -1968,7 +1968,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINSTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Winston3), .party = {.ItemDefaultMoves = sParty_Winston3}, }, @@ -1982,7 +1982,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINSTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Winston4), .party = {.ItemDefaultMoves = sParty_Winston4}, }, @@ -1996,7 +1996,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINSTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Winston5), .party = {.ItemCustomMoves = sParty_Winston5}, }, @@ -2010,7 +2010,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("STEVE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Steve1), .party = {.NoItemDefaultMoves = sParty_Steve1}, }, @@ -2024,7 +2024,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("THALIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Thalia1), .party = {.NoItemDefaultMoves = sParty_Thalia1}, }, @@ -2038,7 +2038,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Mark), .party = {.NoItemDefaultMoves = sParty_Mark}, }, @@ -2052,7 +2052,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMtChimney1), .party = {.NoItemDefaultMoves = sParty_GruntMtChimney1}, }, @@ -2066,7 +2066,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("STEVE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Steve2), .party = {.NoItemDefaultMoves = sParty_Steve2}, }, @@ -2080,7 +2080,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("STEVE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Steve3), .party = {.NoItemDefaultMoves = sParty_Steve3}, }, @@ -2094,7 +2094,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("STEVE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Steve4), .party = {.NoItemDefaultMoves = sParty_Steve4}, }, @@ -2108,7 +2108,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("STEVE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Steve5), .party = {.NoItemDefaultMoves = sParty_Steve5}, }, @@ -2122,7 +2122,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Luis), .party = {.NoItemDefaultMoves = sParty_Luis}, }, @@ -2136,7 +2136,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DOMINIK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dominik), .party = {.NoItemDefaultMoves = sParty_Dominik}, }, @@ -2150,7 +2150,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DOUGLAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Douglas), .party = {.NoItemDefaultMoves = sParty_Douglas}, }, @@ -2164,7 +2164,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARRIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Darrin), .party = {.NoItemDefaultMoves = sParty_Darrin}, }, @@ -2178,7 +2178,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TONY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tony1), .party = {.NoItemDefaultMoves = sParty_Tony1}, }, @@ -2192,7 +2192,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEROME"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jerome), .party = {.NoItemDefaultMoves = sParty_Jerome}, }, @@ -2206,7 +2206,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MATTHEW"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Matthew), .party = {.NoItemDefaultMoves = sParty_Matthew}, }, @@ -2220,7 +2220,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAVID"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_David), .party = {.NoItemDefaultMoves = sParty_David}, }, @@ -2234,7 +2234,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SPENCER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Spencer), .party = {.NoItemDefaultMoves = sParty_Spencer}, }, @@ -2248,7 +2248,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROLAND"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Roland), .party = {.NoItemDefaultMoves = sParty_Roland}, }, @@ -2262,7 +2262,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOLEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nolen), .party = {.NoItemDefaultMoves = sParty_Nolen}, }, @@ -2276,7 +2276,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("STAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Stan), .party = {.NoItemDefaultMoves = sParty_Stan}, }, @@ -2290,7 +2290,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BARRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Barry), .party = {.NoItemDefaultMoves = sParty_Barry}, }, @@ -2304,7 +2304,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DEAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dean), .party = {.NoItemDefaultMoves = sParty_Dean}, }, @@ -2318,7 +2318,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RODNEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Rodney), .party = {.NoItemDefaultMoves = sParty_Rodney}, }, @@ -2332,7 +2332,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICHARD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Richard), .party = {.NoItemDefaultMoves = sParty_Richard}, }, @@ -2346,7 +2346,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HERMAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Herman), .party = {.NoItemDefaultMoves = sParty_Herman}, }, @@ -2360,7 +2360,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SANTIAGO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Santiago), .party = {.NoItemDefaultMoves = sParty_Santiago}, }, @@ -2374,7 +2374,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GILBERT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Gilbert), .party = {.NoItemDefaultMoves = sParty_Gilbert}, }, @@ -2388,7 +2388,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FRANKLIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Franklin), .party = {.NoItemDefaultMoves = sParty_Franklin}, }, @@ -2402,7 +2402,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KEVIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kevin), .party = {.NoItemDefaultMoves = sParty_Kevin}, }, @@ -2416,7 +2416,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jack), .party = {.NoItemDefaultMoves = sParty_Jack}, }, @@ -2430,7 +2430,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUDLEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dudley), .party = {.NoItemDefaultMoves = sParty_Dudley}, }, @@ -2444,7 +2444,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHAD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Chad), .party = {.NoItemDefaultMoves = sParty_Chad}, }, @@ -2458,7 +2458,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TONY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tony2), .party = {.NoItemDefaultMoves = sParty_Tony2}, }, @@ -2472,7 +2472,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TONY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tony3), .party = {.NoItemDefaultMoves = sParty_Tony3}, }, @@ -2486,7 +2486,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TONY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tony4), .party = {.NoItemDefaultMoves = sParty_Tony4}, }, @@ -2500,7 +2500,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TONY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tony5), .party = {.NoItemDefaultMoves = sParty_Tony5}, }, @@ -2514,7 +2514,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TAKAO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Takao), .party = {.NoItemDefaultMoves = sParty_Takao}, }, @@ -2528,7 +2528,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HITOSHI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Hitoshi), .party = {.NoItemDefaultMoves = sParty_Hitoshi}, }, @@ -2542,7 +2542,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIYO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kiyo), .party = {.NoItemDefaultMoves = sParty_Kiyo}, }, @@ -2556,7 +2556,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KOICHI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Koichi), .party = {.NoItemDefaultMoves = sParty_Koichi}, }, @@ -2570,7 +2570,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nob1), .party = {.NoItemDefaultMoves = sParty_Nob1}, }, @@ -2584,7 +2584,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nob2), .party = {.NoItemDefaultMoves = sParty_Nob2}, }, @@ -2598,7 +2598,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nob3), .party = {.NoItemDefaultMoves = sParty_Nob3}, }, @@ -2612,7 +2612,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nob4), .party = {.NoItemDefaultMoves = sParty_Nob4}, }, @@ -2626,7 +2626,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nob5), .party = {.ItemDefaultMoves = sParty_Nob5}, }, @@ -2640,7 +2640,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("YUJI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Yuji), .party = {.NoItemDefaultMoves = sParty_Yuji}, }, @@ -2654,7 +2654,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAISUKE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Daisuke), .party = {.NoItemDefaultMoves = sParty_Daisuke}, }, @@ -2668,7 +2668,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ATSUSHI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Atsushi), .party = {.NoItemDefaultMoves = sParty_Atsushi}, }, @@ -2682,7 +2682,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIRK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kirk), .party = {.NoItemCustomMoves = sParty_Kirk}, }, @@ -2696,7 +2696,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntAquaHideout7), .party = {.NoItemDefaultMoves = sParty_GruntAquaHideout7}, }, @@ -2710,7 +2710,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntAquaHideout8), .party = {.NoItemDefaultMoves = sParty_GruntAquaHideout8}, }, @@ -2724,7 +2724,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHAWN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Shawn), .party = {.NoItemDefaultMoves = sParty_Shawn}, }, @@ -2738,7 +2738,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FERNANDO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Fernando1), .party = {.NoItemDefaultMoves = sParty_Fernando1}, }, @@ -2752,7 +2752,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DALTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dalton1), .party = {.NoItemDefaultMoves = sParty_Dalton1}, }, @@ -2766,7 +2766,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DALTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dalton2), .party = {.NoItemDefaultMoves = sParty_Dalton2}, }, @@ -2780,7 +2780,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DALTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dalton3), .party = {.NoItemDefaultMoves = sParty_Dalton3}, }, @@ -2794,7 +2794,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DALTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dalton4), .party = {.NoItemDefaultMoves = sParty_Dalton4}, }, @@ -2808,7 +2808,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DALTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dalton5), .party = {.NoItemDefaultMoves = sParty_Dalton5}, }, @@ -2822,7 +2822,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("COLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cole), .party = {.NoItemDefaultMoves = sParty_Cole}, }, @@ -2836,7 +2836,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFF"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jeff), .party = {.NoItemDefaultMoves = sParty_Jeff}, }, @@ -2850,7 +2850,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AXLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Axle), .party = {.NoItemDefaultMoves = sParty_Axle}, }, @@ -2864,7 +2864,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jace), .party = {.NoItemDefaultMoves = sParty_Jace}, }, @@ -2878,7 +2878,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KEEGAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Keegan), .party = {.NoItemDefaultMoves = sParty_Keegan}, }, @@ -2892,7 +2892,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bernie1), .party = {.NoItemDefaultMoves = sParty_Bernie1}, }, @@ -2906,7 +2906,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bernie2), .party = {.NoItemDefaultMoves = sParty_Bernie2}, }, @@ -2920,7 +2920,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bernie3), .party = {.NoItemDefaultMoves = sParty_Bernie3}, }, @@ -2934,7 +2934,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bernie4), .party = {.NoItemDefaultMoves = sParty_Bernie4}, }, @@ -2948,7 +2948,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERNIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bernie5), .party = {.NoItemDefaultMoves = sParty_Bernie5}, }, @@ -2962,7 +2962,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DREW"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Drew), .party = {.NoItemCustomMoves = sParty_Drew}, }, @@ -2976,7 +2976,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BEAU"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Beau), .party = {.NoItemCustomMoves = sParty_Beau}, }, @@ -2990,7 +2990,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LARRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Larry), .party = {.NoItemDefaultMoves = sParty_Larry}, }, @@ -3004,7 +3004,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHANE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Shane), .party = {.NoItemDefaultMoves = sParty_Shane}, }, @@ -3018,7 +3018,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUSTIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Justin), .party = {.NoItemDefaultMoves = sParty_Justin}, }, @@ -3032,7 +3032,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ETHAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ethan1), .party = {.NoItemDefaultMoves = sParty_Ethan1}, }, @@ -3046,7 +3046,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AUTUMN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Autumn), .party = {.NoItemDefaultMoves = sParty_Autumn}, }, @@ -3060,7 +3060,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TRAVIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Travis), .party = {.NoItemDefaultMoves = sParty_Travis}, }, @@ -3074,7 +3074,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ETHAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ethan2), .party = {.NoItemDefaultMoves = sParty_Ethan2}, }, @@ -3088,7 +3088,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ETHAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ethan3), .party = {.NoItemDefaultMoves = sParty_Ethan3}, }, @@ -3102,7 +3102,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ETHAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ethan4), .party = {.NoItemDefaultMoves = sParty_Ethan4}, }, @@ -3116,7 +3116,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ETHAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ethan5), .party = {.NoItemDefaultMoves = sParty_Ethan5}, }, @@ -3130,7 +3130,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Brent), .party = {.NoItemDefaultMoves = sParty_Brent}, }, @@ -3144,7 +3144,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DONALD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Donald), .party = {.NoItemDefaultMoves = sParty_Donald}, }, @@ -3158,7 +3158,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TAYLOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Taylor), .party = {.NoItemDefaultMoves = sParty_Taylor}, }, @@ -3172,7 +3172,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFFREY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jeffrey1), .party = {.NoItemDefaultMoves = sParty_Jeffrey1}, }, @@ -3186,7 +3186,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DEREK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Derek), .party = {.NoItemDefaultMoves = sParty_Derek}, }, @@ -3200,7 +3200,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFFREY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jeffrey2), .party = {.NoItemDefaultMoves = sParty_Jeffrey2}, }, @@ -3214,7 +3214,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFFREY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jeffrey3), .party = {.NoItemDefaultMoves = sParty_Jeffrey3}, }, @@ -3228,7 +3228,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFFREY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jeffrey4), .party = {.NoItemDefaultMoves = sParty_Jeffrey4}, }, @@ -3242,7 +3242,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JEFFREY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jeffrey5), .party = {.ItemDefaultMoves = sParty_Jeffrey5}, }, @@ -3256,7 +3256,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDWARD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Edward), .party = {.NoItemCustomMoves = sParty_Edward}, }, @@ -3270,7 +3270,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PRESTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Preston), .party = {.NoItemDefaultMoves = sParty_Preston}, }, @@ -3284,7 +3284,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VIRGIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Virgil), .party = {.NoItemDefaultMoves = sParty_Virgil}, }, @@ -3298,7 +3298,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BLAKE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Blake), .party = {.NoItemDefaultMoves = sParty_Blake}, }, @@ -3312,7 +3312,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILLIAM"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_William), .party = {.NoItemDefaultMoves = sParty_William}, }, @@ -3326,7 +3326,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOSHUA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Joshua), .party = {.NoItemDefaultMoves = sParty_Joshua}, }, @@ -3340,7 +3340,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMERON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cameron1), .party = {.NoItemDefaultMoves = sParty_Cameron1}, }, @@ -3354,7 +3354,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMERON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cameron2), .party = {.NoItemDefaultMoves = sParty_Cameron2}, }, @@ -3368,7 +3368,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMERON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cameron3), .party = {.NoItemDefaultMoves = sParty_Cameron3}, }, @@ -3382,7 +3382,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMERON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cameron4), .party = {.NoItemDefaultMoves = sParty_Cameron4}, }, @@ -3396,7 +3396,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMERON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cameron5), .party = {.NoItemDefaultMoves = sParty_Cameron5}, }, @@ -3410,7 +3410,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACLYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jaclyn), .party = {.NoItemCustomMoves = sParty_Jaclyn}, }, @@ -3424,7 +3424,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HANNAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Hannah), .party = {.NoItemDefaultMoves = sParty_Hannah}, }, @@ -3438,7 +3438,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAMANTHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Samantha), .party = {.NoItemDefaultMoves = sParty_Samantha}, }, @@ -3452,7 +3452,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAURA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Maura), .party = {.NoItemDefaultMoves = sParty_Maura}, }, @@ -3466,7 +3466,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAYLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kayla), .party = {.NoItemDefaultMoves = sParty_Kayla}, }, @@ -3480,7 +3480,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEXIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Alexis), .party = {.NoItemDefaultMoves = sParty_Alexis}, }, @@ -3494,7 +3494,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jacki1), .party = {.NoItemDefaultMoves = sParty_Jacki1}, }, @@ -3508,7 +3508,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jacki2), .party = {.NoItemDefaultMoves = sParty_Jacki2}, }, @@ -3522,7 +3522,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jacki3), .party = {.NoItemDefaultMoves = sParty_Jacki3}, }, @@ -3536,7 +3536,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jacki4), .party = {.NoItemDefaultMoves = sParty_Jacki4}, }, @@ -3550,7 +3550,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jacki5), .party = {.NoItemDefaultMoves = sParty_Jacki5}, }, @@ -3564,7 +3564,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Walter1), .party = {.NoItemDefaultMoves = sParty_Walter1}, }, @@ -3578,7 +3578,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MICAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Micah), .party = {.NoItemDefaultMoves = sParty_Micah}, }, @@ -3592,7 +3592,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("THOMAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Thomas), .party = {.NoItemDefaultMoves = sParty_Thomas}, }, @@ -3606,7 +3606,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Walter2), .party = {.NoItemDefaultMoves = sParty_Walter2}, }, @@ -3620,7 +3620,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Walter3), .party = {.NoItemCustomMoves = sParty_Walter3}, }, @@ -3634,7 +3634,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Walter4), .party = {.NoItemCustomMoves = sParty_Walter4}, }, @@ -3648,7 +3648,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Walter5), .party = {.NoItemCustomMoves = sParty_Walter5}, }, @@ -3662,7 +3662,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SIDNEY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Sidney), .party = {.ItemCustomMoves = sParty_Sidney}, }, @@ -3676,7 +3676,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PHOEBE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Phoebe), .party = {.ItemCustomMoves = sParty_Phoebe}, }, @@ -3690,7 +3690,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GLACIA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Glacia), .party = {.ItemCustomMoves = sParty_Glacia}, }, @@ -3704,7 +3704,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DRAKE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Drake), .party = {.ItemCustomMoves = sParty_Drake}, }, @@ -3718,7 +3718,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_POTION, ITEM_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne1), .party = {.ItemCustomMoves = sParty_Roxanne1}, }, @@ -3732,7 +3732,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly1), .party = {.ItemCustomMoves = sParty_Brawly1}, }, @@ -3746,7 +3746,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson1), .party = {.ItemCustomMoves = sParty_Wattson1}, }, @@ -3760,7 +3760,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery1), .party = {.ItemCustomMoves = sParty_Flannery1}, }, @@ -3774,7 +3774,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman1), .party = {.ItemCustomMoves = sParty_Norman1}, }, @@ -3788,7 +3788,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona1), .party = {.ItemCustomMoves = sParty_Winona1}, }, @@ -3802,7 +3802,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_HYPER_POTION}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza1), .party = {.ItemCustomMoves = sParty_TateAndLiza1}, }, @@ -3816,7 +3816,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan1), .party = {.ItemCustomMoves = sParty_Juan1}, }, @@ -3830,7 +3830,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jerry1), .party = {.NoItemDefaultMoves = sParty_Jerry1}, }, @@ -3844,7 +3844,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ted), .party = {.NoItemDefaultMoves = sParty_Ted}, }, @@ -3858,7 +3858,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAUL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Paul), .party = {.NoItemDefaultMoves = sParty_Paul}, }, @@ -3872,7 +3872,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jerry2), .party = {.NoItemDefaultMoves = sParty_Jerry2}, }, @@ -3886,7 +3886,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jerry3), .party = {.NoItemDefaultMoves = sParty_Jerry3}, }, @@ -3900,7 +3900,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jerry4), .party = {.NoItemDefaultMoves = sParty_Jerry4}, }, @@ -3914,7 +3914,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jerry5), .party = {.NoItemDefaultMoves = sParty_Jerry5}, }, @@ -3928,7 +3928,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAREN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Karen1), .party = {.NoItemDefaultMoves = sParty_Karen1}, }, @@ -3942,7 +3942,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GEORGIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Georgia), .party = {.NoItemDefaultMoves = sParty_Georgia}, }, @@ -3956,7 +3956,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAREN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Karen2), .party = {.NoItemDefaultMoves = sParty_Karen2}, }, @@ -3970,7 +3970,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAREN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Karen3), .party = {.NoItemDefaultMoves = sParty_Karen3}, }, @@ -3984,7 +3984,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAREN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Karen4), .party = {.NoItemDefaultMoves = sParty_Karen4}, }, @@ -3998,7 +3998,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAREN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Karen5), .party = {.NoItemDefaultMoves = sParty_Karen5}, }, @@ -4012,7 +4012,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATE & JOY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_KateAndJoy), .party = {.NoItemCustomMoves = sParty_KateAndJoy}, }, @@ -4026,7 +4026,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANNA & MEG"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AnnaAndMeg1), .party = {.NoItemCustomMoves = sParty_AnnaAndMeg1}, }, @@ -4040,7 +4040,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANNA & MEG"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AnnaAndMeg2), .party = {.NoItemCustomMoves = sParty_AnnaAndMeg2}, }, @@ -4054,7 +4054,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANNA & MEG"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AnnaAndMeg3), .party = {.NoItemCustomMoves = sParty_AnnaAndMeg3}, }, @@ -4068,7 +4068,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANNA & MEG"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AnnaAndMeg4), .party = {.NoItemCustomMoves = sParty_AnnaAndMeg4}, }, @@ -4082,7 +4082,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANNA & MEG"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AnnaAndMeg5), .party = {.NoItemCustomMoves = sParty_AnnaAndMeg5}, }, @@ -4096,7 +4096,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VICTOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Victor), .party = {.ItemDefaultMoves = sParty_Victor}, }, @@ -4110,7 +4110,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIGUEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Miguel1), .party = {.ItemDefaultMoves = sParty_Miguel1}, }, @@ -4124,7 +4124,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("COLTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Colton), .party = {.ItemCustomMoves = sParty_Colton}, }, @@ -4138,7 +4138,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIGUEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Miguel2), .party = {.ItemDefaultMoves = sParty_Miguel2}, }, @@ -4152,7 +4152,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIGUEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Miguel3), .party = {.ItemDefaultMoves = sParty_Miguel3}, }, @@ -4166,7 +4166,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIGUEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Miguel4), .party = {.ItemDefaultMoves = sParty_Miguel4}, }, @@ -4180,7 +4180,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIGUEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Miguel5), .party = {.ItemDefaultMoves = sParty_Miguel5}, }, @@ -4194,7 +4194,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VICTORIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT, .partySize = ARRAY_COUNT(sParty_Victoria), .party = {.ItemDefaultMoves = sParty_Victoria}, }, @@ -4208,7 +4208,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VANESSA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Vanessa), .party = {.ItemDefaultMoves = sParty_Vanessa}, }, @@ -4222,7 +4222,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BETHANY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bethany), .party = {.ItemDefaultMoves = sParty_Bethany}, }, @@ -4236,7 +4236,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isabel1), .party = {.ItemDefaultMoves = sParty_Isabel1}, }, @@ -4250,7 +4250,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isabel2), .party = {.ItemDefaultMoves = sParty_Isabel2}, }, @@ -4264,7 +4264,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isabel3), .party = {.ItemDefaultMoves = sParty_Isabel3}, }, @@ -4278,7 +4278,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isabel4), .party = {.ItemDefaultMoves = sParty_Isabel4}, }, @@ -4292,7 +4292,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isabel5), .party = {.ItemDefaultMoves = sParty_Isabel5}, }, @@ -4306,7 +4306,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy1), .party = {.NoItemDefaultMoves = sParty_Timothy1}, }, @@ -4320,7 +4320,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy2), .party = {.NoItemCustomMoves = sParty_Timothy2}, }, @@ -4334,7 +4334,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy3), .party = {.NoItemCustomMoves = sParty_Timothy3}, }, @@ -4348,7 +4348,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy4), .party = {.NoItemCustomMoves = sParty_Timothy4}, }, @@ -4362,7 +4362,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy5), .party = {.NoItemCustomMoves = sParty_Timothy5}, }, @@ -4376,7 +4376,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Vicky), .party = {.NoItemCustomMoves = sParty_Vicky}, }, @@ -4390,7 +4390,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby1), .party = {.NoItemDefaultMoves = sParty_Shelby1}, }, @@ -4404,7 +4404,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby2), .party = {.NoItemDefaultMoves = sParty_Shelby2}, }, @@ -4418,7 +4418,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby3), .party = {.NoItemDefaultMoves = sParty_Shelby3}, }, @@ -4432,7 +4432,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby4), .party = {.NoItemDefaultMoves = sParty_Shelby4}, }, @@ -4446,7 +4446,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby5), .party = {.NoItemDefaultMoves = sParty_Shelby5}, }, @@ -4460,7 +4460,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CALVIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Calvin1), .party = {.NoItemDefaultMoves = sParty_Calvin1}, }, @@ -4474,7 +4474,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BILLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Billy), .party = {.NoItemDefaultMoves = sParty_Billy}, }, @@ -4488,7 +4488,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOSH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Josh), .party = {.NoItemCustomMoves = sParty_Josh}, }, @@ -4502,7 +4502,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TOMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tommy), .party = {.NoItemDefaultMoves = sParty_Tommy}, }, @@ -4516,7 +4516,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Joey), .party = {.NoItemDefaultMoves = sParty_Joey}, }, @@ -4530,7 +4530,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ben), .party = {.NoItemCustomMoves = sParty_Ben}, }, @@ -4544,7 +4544,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("QUINCY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Quincy), .party = {.NoItemCustomMoves = sParty_Quincy}, }, @@ -4558,7 +4558,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYNN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Katelynn), .party = {.NoItemCustomMoves = sParty_Katelynn}, }, @@ -4572,7 +4572,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAYLEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jaylen), .party = {.NoItemDefaultMoves = sParty_Jaylen}, }, @@ -4586,7 +4586,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DILLON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dillon), .party = {.NoItemDefaultMoves = sParty_Dillon}, }, @@ -4600,7 +4600,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CALVIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Calvin2), .party = {.NoItemDefaultMoves = sParty_Calvin2}, }, @@ -4614,7 +4614,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CALVIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Calvin3), .party = {.NoItemDefaultMoves = sParty_Calvin3}, }, @@ -4628,7 +4628,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CALVIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Calvin4), .party = {.NoItemDefaultMoves = sParty_Calvin4}, }, @@ -4642,7 +4642,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CALVIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Calvin5), .party = {.NoItemDefaultMoves = sParty_Calvin5}, }, @@ -4656,7 +4656,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDDIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Eddie), .party = {.NoItemDefaultMoves = sParty_Eddie}, }, @@ -4670,7 +4670,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALLEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Allen), .party = {.NoItemDefaultMoves = sParty_Allen}, }, @@ -4684,7 +4684,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMMY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Timmy), .party = {.NoItemDefaultMoves = sParty_Timmy}, }, @@ -4698,7 +4698,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLACE"), .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, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wallace), .party = {.ItemCustomMoves = sParty_Wallace}, }, @@ -4712,7 +4712,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANDREW"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Andrew), .party = {.NoItemDefaultMoves = sParty_Andrew}, }, @@ -4726,7 +4726,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("IVAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ivan), .party = {.NoItemDefaultMoves = sParty_Ivan}, }, @@ -4740,7 +4740,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CLAUDE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Claude), .party = {.NoItemDefaultMoves = sParty_Claude}, }, @@ -4754,7 +4754,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELLIOT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Elliot1), .party = {.NoItemDefaultMoves = sParty_Elliot1}, }, @@ -4768,7 +4768,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ned), .party = {.NoItemDefaultMoves = sParty_Ned}, }, @@ -4782,7 +4782,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DALE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dale), .party = {.NoItemDefaultMoves = sParty_Dale}, }, @@ -4796,7 +4796,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOLAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nolan), .party = {.NoItemDefaultMoves = sParty_Nolan}, }, @@ -4810,7 +4810,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BARNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Barny), .party = {.NoItemDefaultMoves = sParty_Barny}, }, @@ -4824,7 +4824,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WADE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Wade), .party = {.NoItemDefaultMoves = sParty_Wade}, }, @@ -4838,7 +4838,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CARTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Carter), .party = {.NoItemDefaultMoves = sParty_Carter}, }, @@ -4852,7 +4852,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELLIOT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Elliot2), .party = {.NoItemDefaultMoves = sParty_Elliot2}, }, @@ -4866,7 +4866,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELLIOT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Elliot3), .party = {.NoItemDefaultMoves = sParty_Elliot3}, }, @@ -4880,7 +4880,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELLIOT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Elliot4), .party = {.NoItemDefaultMoves = sParty_Elliot4}, }, @@ -4894,7 +4894,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELLIOT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT, .partySize = ARRAY_COUNT(sParty_Elliot5), .party = {.NoItemDefaultMoves = sParty_Elliot5}, }, @@ -4908,7 +4908,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RONALD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ronald), .party = {.NoItemDefaultMoves = sParty_Ronald}, }, @@ -4922,7 +4922,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACOB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jacob), .party = {.NoItemDefaultMoves = sParty_Jacob}, }, @@ -4936,7 +4936,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANTHONY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Anthony), .party = {.NoItemDefaultMoves = sParty_Anthony}, }, @@ -4950,7 +4950,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENJAMIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Benjamin1), .party = {.NoItemDefaultMoves = sParty_Benjamin1}, }, @@ -4964,7 +4964,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENJAMIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Benjamin2), .party = {.NoItemDefaultMoves = sParty_Benjamin2}, }, @@ -4978,7 +4978,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENJAMIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Benjamin3), .party = {.NoItemDefaultMoves = sParty_Benjamin3}, }, @@ -4992,7 +4992,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENJAMIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Benjamin4), .party = {.NoItemDefaultMoves = sParty_Benjamin4}, }, @@ -5006,7 +5006,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENJAMIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Benjamin5), .party = {.NoItemDefaultMoves = sParty_Benjamin5}, }, @@ -5020,7 +5020,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ABIGAIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Abigail1), .party = {.NoItemDefaultMoves = sParty_Abigail1}, }, @@ -5034,7 +5034,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JASMINE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jasmine), .party = {.NoItemDefaultMoves = sParty_Jasmine}, }, @@ -5048,7 +5048,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ABIGAIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Abigail2), .party = {.NoItemDefaultMoves = sParty_Abigail2}, }, @@ -5062,7 +5062,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ABIGAIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Abigail3), .party = {.NoItemDefaultMoves = sParty_Abigail3}, }, @@ -5076,7 +5076,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ABIGAIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Abigail4), .party = {.NoItemDefaultMoves = sParty_Abigail4}, }, @@ -5090,7 +5090,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ABIGAIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Abigail5), .party = {.NoItemDefaultMoves = sParty_Abigail5}, }, @@ -5104,7 +5104,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DYLAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dylan1), .party = {.NoItemDefaultMoves = sParty_Dylan1}, }, @@ -5118,7 +5118,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DYLAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dylan2), .party = {.NoItemDefaultMoves = sParty_Dylan2}, }, @@ -5132,7 +5132,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DYLAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dylan3), .party = {.NoItemDefaultMoves = sParty_Dylan3}, }, @@ -5146,7 +5146,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DYLAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dylan4), .party = {.NoItemDefaultMoves = sParty_Dylan4}, }, @@ -5160,7 +5160,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DYLAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dylan5), .party = {.NoItemDefaultMoves = sParty_Dylan5}, }, @@ -5174,7 +5174,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Maria1), .party = {.NoItemDefaultMoves = sParty_Maria1}, }, @@ -5188,7 +5188,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Maria2), .party = {.NoItemDefaultMoves = sParty_Maria2}, }, @@ -5202,7 +5202,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Maria3), .party = {.NoItemDefaultMoves = sParty_Maria3}, }, @@ -5216,7 +5216,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Maria4), .party = {.NoItemDefaultMoves = sParty_Maria4}, }, @@ -5230,7 +5230,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Maria5), .party = {.NoItemDefaultMoves = sParty_Maria5}, }, @@ -5244,7 +5244,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMDEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Camden), .party = {.NoItemDefaultMoves = sParty_Camden}, }, @@ -5258,7 +5258,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DEMETRIUS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Demetrius), .party = {.NoItemDefaultMoves = sParty_Demetrius}, }, @@ -5272,7 +5272,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAIAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaiah1), .party = {.NoItemDefaultMoves = sParty_Isaiah1}, }, @@ -5286,7 +5286,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PABLO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Pablo1), .party = {.NoItemDefaultMoves = sParty_Pablo1}, }, @@ -5300,7 +5300,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHASE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Chase), .party = {.NoItemDefaultMoves = sParty_Chase}, }, @@ -5314,7 +5314,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAIAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaiah2), .party = {.NoItemDefaultMoves = sParty_Isaiah2}, }, @@ -5328,7 +5328,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAIAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaiah3), .party = {.NoItemDefaultMoves = sParty_Isaiah3}, }, @@ -5342,7 +5342,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAIAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaiah4), .party = {.NoItemDefaultMoves = sParty_Isaiah4}, }, @@ -5356,7 +5356,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAIAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaiah5), .party = {.NoItemDefaultMoves = sParty_Isaiah5}, }, @@ -5370,7 +5370,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISOBEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isobel), .party = {.NoItemDefaultMoves = sParty_Isobel}, }, @@ -5384,7 +5384,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DONNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Donny), .party = {.NoItemDefaultMoves = sParty_Donny}, }, @@ -5398,7 +5398,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TALIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Talia), .party = {.NoItemDefaultMoves = sParty_Talia}, }, @@ -5412,7 +5412,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Katelyn1), .party = {.NoItemDefaultMoves = sParty_Katelyn1}, }, @@ -5426,7 +5426,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALLISON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Allison), .party = {.NoItemDefaultMoves = sParty_Allison}, }, @@ -5440,7 +5440,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Katelyn2), .party = {.NoItemDefaultMoves = sParty_Katelyn2}, }, @@ -5454,7 +5454,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Katelyn3), .party = {.NoItemDefaultMoves = sParty_Katelyn3}, }, @@ -5468,7 +5468,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Katelyn4), .party = {.NoItemDefaultMoves = sParty_Katelyn4}, }, @@ -5482,7 +5482,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Katelyn5), .party = {.NoItemDefaultMoves = sParty_Katelyn5}, }, @@ -5496,7 +5496,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICOLAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nicolas1), .party = {.NoItemDefaultMoves = sParty_Nicolas1}, }, @@ -5510,7 +5510,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICOLAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nicolas2), .party = {.NoItemDefaultMoves = sParty_Nicolas2}, }, @@ -5524,7 +5524,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICOLAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nicolas3), .party = {.NoItemDefaultMoves = sParty_Nicolas3}, }, @@ -5538,7 +5538,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICOLAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nicolas4), .party = {.NoItemDefaultMoves = sParty_Nicolas4}, }, @@ -5552,7 +5552,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICOLAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nicolas5), .party = {.ItemDefaultMoves = sParty_Nicolas5}, }, @@ -5566,7 +5566,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AARON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Aaron), .party = {.NoItemCustomMoves = sParty_Aaron}, }, @@ -5580,7 +5580,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Perry), .party = {.NoItemDefaultMoves = sParty_Perry}, }, @@ -5594,7 +5594,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HUGH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Hugh), .party = {.NoItemDefaultMoves = sParty_Hugh}, }, @@ -5608,7 +5608,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PHIL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Phil), .party = {.NoItemDefaultMoves = sParty_Phil}, }, @@ -5622,7 +5622,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JARED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jared), .party = {.NoItemDefaultMoves = sParty_Jared}, }, @@ -5636,7 +5636,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HUMBERTO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Humberto), .party = {.NoItemDefaultMoves = sParty_Humberto}, }, @@ -5650,7 +5650,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PRESLEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Presley), .party = {.NoItemDefaultMoves = sParty_Presley}, }, @@ -5664,7 +5664,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDWARDO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Edwardo), .party = {.NoItemDefaultMoves = sParty_Edwardo}, }, @@ -5678,7 +5678,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("COLIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Colin), .party = {.NoItemDefaultMoves = sParty_Colin}, }, @@ -5692,7 +5692,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBERT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Robert1), .party = {.NoItemDefaultMoves = sParty_Robert1}, }, @@ -5706,7 +5706,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Benny), .party = {.NoItemDefaultMoves = sParty_Benny}, }, @@ -5720,7 +5720,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHESTER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Chester), .party = {.NoItemDefaultMoves = sParty_Chester}, }, @@ -5734,7 +5734,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBERT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Robert2), .party = {.NoItemDefaultMoves = sParty_Robert2}, }, @@ -5748,7 +5748,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBERT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Robert3), .party = {.NoItemDefaultMoves = sParty_Robert3}, }, @@ -5762,7 +5762,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBERT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Robert4), .party = {.NoItemDefaultMoves = sParty_Robert4}, }, @@ -5776,7 +5776,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBERT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Robert5), .party = {.NoItemDefaultMoves = sParty_Robert5}, }, @@ -5790,7 +5790,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEX"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Alex), .party = {.NoItemDefaultMoves = sParty_Alex}, }, @@ -5804,7 +5804,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BECK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Beck), .party = {.NoItemDefaultMoves = sParty_Beck}, }, @@ -5818,7 +5818,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("YASU"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT, .partySize = ARRAY_COUNT(sParty_Yasu), .party = {.NoItemDefaultMoves = sParty_Yasu}, }, @@ -5832,7 +5832,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TAKASHI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT, .partySize = ARRAY_COUNT(sParty_Takashi), .party = {.NoItemDefaultMoves = sParty_Takashi}, }, @@ -5958,7 +5958,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOCELYN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jocelyn), .party = {.NoItemDefaultMoves = sParty_Jocelyn}, }, @@ -5972,7 +5972,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAURA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Laura), .party = {.NoItemDefaultMoves = sParty_Laura}, }, @@ -5986,7 +5986,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CYNDY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cyndy1), .party = {.NoItemDefaultMoves = sParty_Cyndy1}, }, @@ -6000,7 +6000,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CORA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cora), .party = {.NoItemDefaultMoves = sParty_Cora}, }, @@ -6014,7 +6014,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAULA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Paula), .party = {.NoItemDefaultMoves = sParty_Paula}, }, @@ -6028,7 +6028,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CYNDY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cyndy2), .party = {.NoItemDefaultMoves = sParty_Cyndy2}, }, @@ -6042,7 +6042,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CYNDY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cyndy3), .party = {.NoItemDefaultMoves = sParty_Cyndy3}, }, @@ -6056,7 +6056,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CYNDY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cyndy4), .party = {.NoItemDefaultMoves = sParty_Cyndy4}, }, @@ -6070,7 +6070,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CYNDY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cyndy5), .party = {.NoItemDefaultMoves = sParty_Cyndy5}, }, @@ -6084,7 +6084,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MADELINE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Madeline1), .party = {.NoItemCustomMoves = sParty_Madeline1}, }, @@ -6098,7 +6098,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CLARISSA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Clarissa), .party = {.NoItemDefaultMoves = sParty_Clarissa}, }, @@ -6112,7 +6112,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANGELICA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Angelica), .party = {.NoItemCustomMoves = sParty_Angelica}, }, @@ -6126,7 +6126,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MADELINE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Madeline2), .party = {.NoItemCustomMoves = sParty_Madeline2}, }, @@ -6140,7 +6140,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MADELINE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Madeline3), .party = {.NoItemCustomMoves = sParty_Madeline3}, }, @@ -6154,7 +6154,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MADELINE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Madeline4), .party = {.NoItemCustomMoves = sParty_Madeline4}, }, @@ -6168,7 +6168,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MADELINE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Madeline5), .party = {.NoItemCustomMoves = sParty_Madeline5}, }, @@ -6182,7 +6182,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BEVERLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Beverly), .party = {.NoItemDefaultMoves = sParty_Beverly}, }, @@ -6196,7 +6196,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("IMANI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Imani), .party = {.NoItemDefaultMoves = sParty_Imani}, }, @@ -6210,7 +6210,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KYLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kyla), .party = {.NoItemDefaultMoves = sParty_Kyla}, }, @@ -6224,7 +6224,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DENISE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Denise), .party = {.NoItemDefaultMoves = sParty_Denise}, }, @@ -6238,7 +6238,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BETH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Beth), .party = {.NoItemDefaultMoves = sParty_Beth}, }, @@ -6252,7 +6252,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TARA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tara), .party = {.NoItemDefaultMoves = sParty_Tara}, }, @@ -6266,7 +6266,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MISSY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Missy), .party = {.NoItemDefaultMoves = sParty_Missy}, }, @@ -6280,7 +6280,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALICE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Alice), .party = {.NoItemDefaultMoves = sParty_Alice}, }, @@ -6294,7 +6294,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jenny1), .party = {.NoItemDefaultMoves = sParty_Jenny1}, }, @@ -6308,7 +6308,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRACE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Grace), .party = {.NoItemDefaultMoves = sParty_Grace}, }, @@ -6322,7 +6322,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TANYA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tanya), .party = {.NoItemDefaultMoves = sParty_Tanya}, }, @@ -6336,7 +6336,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHARON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Sharon), .party = {.NoItemDefaultMoves = sParty_Sharon}, }, @@ -6350,7 +6350,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NIKKI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nikki), .party = {.NoItemDefaultMoves = sParty_Nikki}, }, @@ -6364,7 +6364,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Brenda), .party = {.NoItemDefaultMoves = sParty_Brenda}, }, @@ -6378,7 +6378,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Katie), .party = {.NoItemDefaultMoves = sParty_Katie}, }, @@ -6392,7 +6392,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SUSIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Susie), .party = {.NoItemDefaultMoves = sParty_Susie}, }, @@ -6406,7 +6406,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KARA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kara), .party = {.NoItemDefaultMoves = sParty_Kara}, }, @@ -6420,7 +6420,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dana), .party = {.NoItemDefaultMoves = sParty_Dana}, }, @@ -6434,7 +6434,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SIENNA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Sienna), .party = {.NoItemDefaultMoves = sParty_Sienna}, }, @@ -6448,7 +6448,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DEBRA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Debra), .party = {.NoItemDefaultMoves = sParty_Debra}, }, @@ -6462,7 +6462,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LINDA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Linda), .party = {.NoItemDefaultMoves = sParty_Linda}, }, @@ -6476,7 +6476,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAYLEE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kaylee), .party = {.NoItemDefaultMoves = sParty_Kaylee}, }, @@ -6490,7 +6490,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAUREL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Laurel), .party = {.NoItemDefaultMoves = sParty_Laurel}, }, @@ -6504,7 +6504,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CARLEE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Carlee), .party = {.NoItemDefaultMoves = sParty_Carlee}, }, @@ -6518,7 +6518,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jenny2), .party = {.NoItemDefaultMoves = sParty_Jenny2}, }, @@ -6532,7 +6532,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jenny3), .party = {.NoItemDefaultMoves = sParty_Jenny3}, }, @@ -6546,7 +6546,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jenny4), .party = {.NoItemDefaultMoves = sParty_Jenny4}, }, @@ -6560,7 +6560,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jenny5), .party = {.NoItemDefaultMoves = sParty_Jenny5}, }, @@ -6574,7 +6574,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HEIDI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Heidi), .party = {.NoItemCustomMoves = sParty_Heidi}, }, @@ -6588,7 +6588,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BECKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Becky), .party = {.NoItemCustomMoves = sParty_Becky}, }, @@ -6602,7 +6602,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAROL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Carol), .party = {.NoItemDefaultMoves = sParty_Carol}, }, @@ -6616,7 +6616,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NANCY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nancy), .party = {.NoItemDefaultMoves = sParty_Nancy}, }, @@ -6630,7 +6630,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARTHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Martha), .party = {.NoItemDefaultMoves = sParty_Martha}, }, @@ -6644,7 +6644,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DIANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Diana1), .party = {.NoItemDefaultMoves = sParty_Diana1}, }, @@ -6658,7 +6658,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CEDRIC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cedric), .party = {.NoItemCustomMoves = sParty_Cedric}, }, @@ -6672,7 +6672,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("IRENE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Irene), .party = {.NoItemDefaultMoves = sParty_Irene}, }, @@ -6686,7 +6686,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DIANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Diana2), .party = {.NoItemDefaultMoves = sParty_Diana2}, }, @@ -6700,7 +6700,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DIANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Diana3), .party = {.NoItemDefaultMoves = sParty_Diana3}, }, @@ -6714,7 +6714,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DIANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Diana4), .party = {.NoItemDefaultMoves = sParty_Diana4}, }, @@ -6728,7 +6728,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DIANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Diana5), .party = {.NoItemDefaultMoves = sParty_Diana5}, }, @@ -6742,7 +6742,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMY & LIV"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AmyAndLiv1), .party = {.NoItemDefaultMoves = sParty_AmyAndLiv1}, }, @@ -6756,7 +6756,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMY & LIV"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AmyAndLiv2), .party = {.NoItemDefaultMoves = sParty_AmyAndLiv2}, }, @@ -6770,7 +6770,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GINA & MIA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GinaAndMia1), .party = {.NoItemDefaultMoves = sParty_GinaAndMia1}, }, @@ -6784,7 +6784,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIU & YUKI"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_MiuAndYuki), .party = {.NoItemDefaultMoves = sParty_MiuAndYuki}, }, @@ -6798,7 +6798,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMY & LIV"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AmyAndLiv3), .party = {.NoItemDefaultMoves = sParty_AmyAndLiv3}, }, @@ -6812,7 +6812,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GINA & MIA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GinaAndMia2), .party = {.NoItemCustomMoves = sParty_GinaAndMia2}, }, @@ -6826,7 +6826,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMY & LIV"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AmyAndLiv4), .party = {.NoItemDefaultMoves = sParty_AmyAndLiv4}, }, @@ -6840,7 +6840,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMY & LIV"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AmyAndLiv5), .party = {.NoItemCustomMoves = sParty_AmyAndLiv5}, }, @@ -6854,7 +6854,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AMY & LIV"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_AmyAndLiv6), .party = {.NoItemCustomMoves = sParty_AmyAndLiv6}, }, @@ -6868,7 +6868,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HUEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Huey), .party = {.NoItemDefaultMoves = sParty_Huey}, }, @@ -6882,7 +6882,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDMOND"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Edmond), .party = {.NoItemDefaultMoves = sParty_Edmond}, }, @@ -6896,7 +6896,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERNEST"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ernest1), .party = {.NoItemDefaultMoves = sParty_Ernest1}, }, @@ -6910,7 +6910,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DWAYNE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dwayne), .party = {.NoItemDefaultMoves = sParty_Dwayne}, }, @@ -6924,7 +6924,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PHILLIP"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Phillip), .party = {.NoItemDefaultMoves = sParty_Phillip}, }, @@ -6938,7 +6938,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEONARD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Leonard), .party = {.NoItemDefaultMoves = sParty_Leonard}, }, @@ -6952,7 +6952,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DUNCAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Duncan), .party = {.NoItemDefaultMoves = sParty_Duncan}, }, @@ -6966,7 +6966,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERNEST"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ernest2), .party = {.NoItemDefaultMoves = sParty_Ernest2}, }, @@ -6980,7 +6980,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERNEST"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ernest3), .party = {.NoItemDefaultMoves = sParty_Ernest3}, }, @@ -6994,7 +6994,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERNEST"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ernest4), .party = {.NoItemDefaultMoves = sParty_Ernest4}, }, @@ -7008,7 +7008,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERNEST"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ernest5), .party = {.NoItemDefaultMoves = sParty_Ernest5}, }, @@ -7022,7 +7022,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Eli), .party = {.NoItemDefaultMoves = sParty_Eli}, }, @@ -7036,7 +7036,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANNIKA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Annika), .party = {.ItemCustomMoves = sParty_Annika}, }, @@ -7050,7 +7050,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAZMYN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jazmyn), .party = {.NoItemDefaultMoves = sParty_Jazmyn}, }, @@ -7064,7 +7064,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JONAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jonas), .party = {.NoItemCustomMoves = sParty_Jonas}, }, @@ -7078,7 +7078,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAYLEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kayley), .party = {.NoItemCustomMoves = sParty_Kayley}, }, @@ -7092,7 +7092,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AURON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Auron), .party = {.NoItemDefaultMoves = sParty_Auron}, }, @@ -7106,7 +7106,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KELVIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kelvin), .party = {.NoItemDefaultMoves = sParty_Kelvin}, }, @@ -7120,7 +7120,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARLEY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Marley), .party = {.ItemCustomMoves = sParty_Marley}, }, @@ -7134,7 +7134,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("REYNA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Reyna), .party = {.NoItemDefaultMoves = sParty_Reyna}, }, @@ -7148,7 +7148,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HUDSON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Hudson), .party = {.NoItemDefaultMoves = sParty_Hudson}, }, @@ -7162,7 +7162,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CONOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Conor), .party = {.NoItemDefaultMoves = sParty_Conor}, }, @@ -7176,7 +7176,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDWIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Edwin1), .party = {.NoItemDefaultMoves = sParty_Edwin1}, }, @@ -7190,7 +7190,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HECTOR"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Hector), .party = {.NoItemDefaultMoves = sParty_Hector}, }, @@ -7204,7 +7204,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TABITHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_TabithaMossdeep), .party = {.NoItemDefaultMoves = sParty_TabithaMossdeep}, }, @@ -7218,7 +7218,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDWIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Edwin2), .party = {.NoItemDefaultMoves = sParty_Edwin2}, }, @@ -7232,7 +7232,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDWIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Edwin3), .party = {.NoItemDefaultMoves = sParty_Edwin3}, }, @@ -7246,7 +7246,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDWIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Edwin4), .party = {.NoItemDefaultMoves = sParty_Edwin4}, }, @@ -7260,7 +7260,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDWIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Edwin5), .party = {.NoItemDefaultMoves = sParty_Edwin5}, }, @@ -7274,7 +7274,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR1), .party = {.NoItemCustomMoves = sParty_WallyVR1}, }, @@ -7288,7 +7288,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute103Mudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRoute103Mudkip}, }, @@ -7302,7 +7302,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute110Mudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRoute110Mudkip}, }, @@ -7316,7 +7316,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute119Mudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRoute119Mudkip}, }, @@ -7330,7 +7330,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_BrendanRoute103Treecko), .party = {.NoItemDefaultMoves = sParty_BrendanRoute103Treecko}, }, @@ -7344,7 +7344,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute110Treecko), .party = {.NoItemDefaultMoves = sParty_BrendanRoute110Treecko}, }, @@ -7358,7 +7358,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute119Treecko), .party = {.NoItemDefaultMoves = sParty_BrendanRoute119Treecko}, }, @@ -7372,7 +7372,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute103Torchic), .party = {.NoItemDefaultMoves = sParty_BrendanRoute103Torchic}, }, @@ -7386,7 +7386,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute110Torchic), .party = {.NoItemDefaultMoves = sParty_BrendanRoute110Torchic}, }, @@ -7400,7 +7400,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute119Torchic), .party = {.NoItemDefaultMoves = sParty_BrendanRoute119Torchic}, }, @@ -7414,7 +7414,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute103Mudkip), .party = {.NoItemDefaultMoves = sParty_MayRoute103Mudkip}, }, @@ -7428,7 +7428,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute110Mudkip), .party = {.NoItemDefaultMoves = sParty_MayRoute110Mudkip}, }, @@ -7442,7 +7442,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute119Mudkip), .party = {.NoItemDefaultMoves = sParty_MayRoute119Mudkip}, }, @@ -7456,7 +7456,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute103Treecko), .party = {.NoItemDefaultMoves = sParty_MayRoute103Treecko}, }, @@ -7470,7 +7470,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute110Treecko), .party = {.NoItemDefaultMoves = sParty_MayRoute110Treecko}, }, @@ -7484,7 +7484,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute119Treecko), .party = {.NoItemDefaultMoves = sParty_MayRoute119Treecko}, }, @@ -7498,7 +7498,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute103Torchic), .party = {.NoItemDefaultMoves = sParty_MayRoute103Torchic}, }, @@ -7512,7 +7512,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute110Torchic), .party = {.NoItemDefaultMoves = sParty_MayRoute110Torchic}, }, @@ -7526,7 +7526,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute119Torchic), .party = {.NoItemDefaultMoves = sParty_MayRoute119Torchic}, }, @@ -7540,7 +7540,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAAC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaac1), .party = {.NoItemDefaultMoves = sParty_Isaac1}, }, @@ -7554,7 +7554,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAVIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Davis), .party = {.NoItemDefaultMoves = sParty_Davis}, }, @@ -7568,7 +7568,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MITCHELL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Mitchell), .party = {.NoItemCustomMoves = sParty_Mitchell}, }, @@ -7582,7 +7582,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAAC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaac2), .party = {.NoItemDefaultMoves = sParty_Isaac2}, }, @@ -7596,7 +7596,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAAC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaac3), .party = {.NoItemDefaultMoves = sParty_Isaac3}, }, @@ -7610,7 +7610,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAAC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaac4), .party = {.NoItemDefaultMoves = sParty_Isaac4}, }, @@ -7624,7 +7624,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISAAC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isaac5), .party = {.NoItemDefaultMoves = sParty_Isaac5}, }, @@ -7638,7 +7638,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LYDIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lydia1), .party = {.NoItemDefaultMoves = sParty_Lydia1}, }, @@ -7652,7 +7652,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HALLE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Halle), .party = {.NoItemDefaultMoves = sParty_Halle}, }, @@ -7666,7 +7666,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GARRISON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Garrison), .party = {.NoItemDefaultMoves = sParty_Garrison}, }, @@ -7680,7 +7680,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LYDIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lydia2), .party = {.NoItemDefaultMoves = sParty_Lydia2}, }, @@ -7694,7 +7694,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LYDIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lydia3), .party = {.NoItemDefaultMoves = sParty_Lydia3}, }, @@ -7708,7 +7708,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LYDIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lydia4), .party = {.NoItemDefaultMoves = sParty_Lydia4}, }, @@ -7722,7 +7722,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LYDIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lydia5), .party = {.NoItemDefaultMoves = sParty_Lydia5}, }, @@ -7736,7 +7736,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jackson1), .party = {.NoItemDefaultMoves = sParty_Jackson1}, }, @@ -7750,7 +7750,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LORENZO"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Lorenzo), .party = {.NoItemDefaultMoves = sParty_Lorenzo}, }, @@ -7764,7 +7764,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SEBASTIAN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sebastian), .party = {.NoItemDefaultMoves = sParty_Sebastian}, }, @@ -7778,7 +7778,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Jackson2), .party = {.NoItemDefaultMoves = sParty_Jackson2}, }, @@ -7792,7 +7792,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jackson3), .party = {.NoItemDefaultMoves = sParty_Jackson3}, }, @@ -7806,7 +7806,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Jackson4), .party = {.NoItemDefaultMoves = sParty_Jackson4}, }, @@ -7820,7 +7820,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jackson5), .party = {.NoItemDefaultMoves = sParty_Jackson5}, }, @@ -7834,7 +7834,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CATHERINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Catherine1), .party = {.NoItemDefaultMoves = sParty_Catherine1}, }, @@ -7848,7 +7848,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNA"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Jenna), .party = {.NoItemDefaultMoves = sParty_Jenna}, }, @@ -7862,7 +7862,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SOPHIA"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sophia), .party = {.NoItemDefaultMoves = sParty_Sophia}, }, @@ -7876,7 +7876,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CATHERINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Catherine2), .party = {.NoItemDefaultMoves = sParty_Catherine2}, }, @@ -7890,7 +7890,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CATHERINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Catherine3), .party = {.NoItemDefaultMoves = sParty_Catherine3}, }, @@ -7904,7 +7904,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CATHERINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Catherine4), .party = {.NoItemDefaultMoves = sParty_Catherine4}, }, @@ -7918,7 +7918,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CATHERINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Catherine5), .party = {.NoItemDefaultMoves = sParty_Catherine5}, }, @@ -7932,7 +7932,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JULIO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Julio), .party = {.NoItemDefaultMoves = sParty_Julio}, }, @@ -7946,7 +7946,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSeafloorCavern5), .party = {.NoItemDefaultMoves = sParty_GruntSeafloorCavern5}, }, @@ -7960,7 +7960,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntUnused), .party = {.NoItemDefaultMoves = sParty_GruntUnused}, }, @@ -7974,7 +7974,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMtPyre4), .party = {.NoItemDefaultMoves = sParty_GruntMtPyre4}, }, @@ -7988,7 +7988,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntJaggedPass), .party = {.NoItemDefaultMoves = sParty_GruntJaggedPass}, }, @@ -8002,7 +8002,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Marc), .party = {.NoItemDefaultMoves = sParty_Marc}, }, @@ -8016,7 +8016,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Brenden), .party = {.NoItemDefaultMoves = sParty_Brenden}, }, @@ -8030,7 +8030,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LILITH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lilith), .party = {.NoItemDefaultMoves = sParty_Lilith}, }, @@ -8044,7 +8044,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cristian), .party = {.NoItemDefaultMoves = sParty_Cristian}, }, @@ -8058,7 +8058,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SYLVIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Sylvia), .party = {.NoItemDefaultMoves = sParty_Sylvia}, }, @@ -8072,7 +8072,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEONARDO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Leonardo), .party = {.NoItemDefaultMoves = sParty_Leonardo}, }, @@ -8086,7 +8086,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ATHENA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Athena), .party = {.ItemCustomMoves = sParty_Athena}, }, @@ -8100,7 +8100,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HARRISON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Harrison), .party = {.NoItemDefaultMoves = sParty_Harrison}, }, @@ -8114,7 +8114,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMtChimney2), .party = {.NoItemDefaultMoves = sParty_GruntMtChimney2}, }, @@ -8128,7 +8128,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CLARENCE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Clarence), .party = {.NoItemDefaultMoves = sParty_Clarence}, }, @@ -8142,7 +8142,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TERRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Terry), .party = {.NoItemDefaultMoves = sParty_Terry}, }, @@ -8156,7 +8156,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NATE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nate), .party = {.NoItemDefaultMoves = sParty_Nate}, }, @@ -8170,7 +8170,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATHLEEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kathleen), .party = {.NoItemDefaultMoves = sParty_Kathleen}, }, @@ -8184,7 +8184,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CLIFFORD"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Clifford), .party = {.NoItemDefaultMoves = sParty_Clifford}, }, @@ -8198,7 +8198,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NICHOLAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Nicholas), .party = {.NoItemDefaultMoves = sParty_Nicholas}, }, @@ -8212,7 +8212,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSpaceCenter3), .party = {.NoItemDefaultMoves = sParty_GruntSpaceCenter3}, }, @@ -8226,7 +8226,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSpaceCenter4), .party = {.NoItemDefaultMoves = sParty_GruntSpaceCenter4}, }, @@ -8240,7 +8240,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSpaceCenter5), .party = {.NoItemDefaultMoves = sParty_GruntSpaceCenter5}, }, @@ -8254,7 +8254,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSpaceCenter6), .party = {.NoItemDefaultMoves = sParty_GruntSpaceCenter6}, }, @@ -8268,7 +8268,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntSpaceCenter7), .party = {.NoItemDefaultMoves = sParty_GruntSpaceCenter7}, }, @@ -8282,7 +8282,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MACEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Macey), .party = {.NoItemDefaultMoves = sParty_Macey}, }, @@ -8296,7 +8296,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRustboroTreecko), .party = {.NoItemDefaultMoves = sParty_BrendanRustboroTreecko}, }, @@ -8310,7 +8310,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRustboroMudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRustboroMudkip}, }, @@ -8324,7 +8324,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAXTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Paxton), .party = {.NoItemDefaultMoves = sParty_Paxton}, }, @@ -8338,7 +8338,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABELLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isabella), .party = {.NoItemDefaultMoves = sParty_Isabella}, }, @@ -8352,7 +8352,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntWeatherInst5), .party = {.NoItemDefaultMoves = sParty_GruntWeatherInst5}, }, @@ -8366,7 +8366,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TABITHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TabithaMtChimney), .party = {.NoItemDefaultMoves = sParty_TabithaMtChimney}, }, @@ -8380,7 +8380,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JONATHAN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Jonathan), .party = {.NoItemDefaultMoves = sParty_Jonathan}, }, @@ -8394,7 +8394,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRustboroTorchic), .party = {.NoItemDefaultMoves = sParty_BrendanRustboroTorchic}, }, @@ -8408,7 +8408,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_MayRustboroMudkip), .party = {.NoItemDefaultMoves = sParty_MayRustboroMudkip}, }, @@ -8422,7 +8422,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAXIE"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MaxieMagmaHideout), .party = {.NoItemDefaultMoves = sParty_MaxieMagmaHideout}, }, @@ -8436,7 +8436,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAXIE"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MaxieMtChimney), .party = {.NoItemDefaultMoves = sParty_MaxieMtChimney}, }, @@ -8450,7 +8450,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIANA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tiana), .party = {.NoItemDefaultMoves = sParty_Tiana}, }, @@ -8464,7 +8464,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HALEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Haley1), .party = {.NoItemDefaultMoves = sParty_Haley1}, }, @@ -8478,7 +8478,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JANICE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Janice), .party = {.NoItemDefaultMoves = sParty_Janice}, }, @@ -8492,7 +8492,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VIVI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Vivi), .party = {.NoItemDefaultMoves = sParty_Vivi}, }, @@ -8506,7 +8506,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HALEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Haley2), .party = {.NoItemDefaultMoves = sParty_Haley2}, }, @@ -8520,7 +8520,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HALEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Haley3), .party = {.NoItemDefaultMoves = sParty_Haley3}, }, @@ -8534,7 +8534,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HALEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Haley4), .party = {.NoItemDefaultMoves = sParty_Haley4}, }, @@ -8548,7 +8548,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HALEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Haley5), .party = {.NoItemDefaultMoves = sParty_Haley5}, }, @@ -8562,7 +8562,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SALLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Sally), .party = {.NoItemDefaultMoves = sParty_Sally}, }, @@ -8576,7 +8576,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROBIN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Robin), .party = {.NoItemDefaultMoves = sParty_Robin}, }, @@ -8590,7 +8590,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANDREA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Andrea), .party = {.NoItemDefaultMoves = sParty_Andrea}, }, @@ -8604,7 +8604,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISSY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Crissy), .party = {.NoItemDefaultMoves = sParty_Crissy}, }, @@ -8618,7 +8618,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RICK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Rick), .party = {.NoItemDefaultMoves = sParty_Rick}, }, @@ -8632,7 +8632,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LYLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lyle), .party = {.NoItemDefaultMoves = sParty_Lyle}, }, @@ -8646,7 +8646,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOSE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jose), .party = {.NoItemDefaultMoves = sParty_Jose}, }, @@ -8660,7 +8660,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DOUG"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Doug), .party = {.NoItemDefaultMoves = sParty_Doug}, }, @@ -8674,7 +8674,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GREG"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Greg), .party = {.NoItemDefaultMoves = sParty_Greg}, }, @@ -8688,7 +8688,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kent), .party = {.NoItemDefaultMoves = sParty_Kent}, }, @@ -8702,7 +8702,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAMES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_James1), .party = {.NoItemDefaultMoves = sParty_James1}, }, @@ -8716,7 +8716,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAMES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_James2), .party = {.NoItemDefaultMoves = sParty_James2}, }, @@ -8730,7 +8730,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAMES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_James3), .party = {.NoItemDefaultMoves = sParty_James3}, }, @@ -8744,7 +8744,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAMES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_James4), .party = {.NoItemDefaultMoves = sParty_James4}, }, @@ -8758,7 +8758,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAMES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_James5), .party = {.NoItemDefaultMoves = sParty_James5}, }, @@ -8772,7 +8772,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRICE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Brice), .party = {.NoItemDefaultMoves = sParty_Brice}, }, @@ -8786,7 +8786,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TRENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Trent1), .party = {.NoItemDefaultMoves = sParty_Trent1}, }, @@ -8800,7 +8800,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LENNY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lenny), .party = {.NoItemDefaultMoves = sParty_Lenny}, }, @@ -8814,7 +8814,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUCAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lucas1), .party = {.NoItemDefaultMoves = sParty_Lucas1}, }, @@ -8828,7 +8828,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Alan), .party = {.NoItemDefaultMoves = sParty_Alan}, }, @@ -8842,7 +8842,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CLARK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Clark), .party = {.NoItemDefaultMoves = sParty_Clark}, }, @@ -8856,7 +8856,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ERIC"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Eric), .party = {.NoItemDefaultMoves = sParty_Eric}, }, @@ -8870,7 +8870,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUCAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lucas2), .party = {.NoItemCustomMoves = sParty_Lucas2}, }, @@ -8884,7 +8884,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIKE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Mike1), .party = {.NoItemCustomMoves = sParty_Mike1}, }, @@ -8898,7 +8898,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MIKE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Mike2), .party = {.NoItemDefaultMoves = sParty_Mike2}, }, @@ -8912,7 +8912,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TRENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Trent2), .party = {.NoItemDefaultMoves = sParty_Trent2}, }, @@ -8926,7 +8926,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TRENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Trent3), .party = {.NoItemDefaultMoves = sParty_Trent3}, }, @@ -8940,7 +8940,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TRENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Trent4), .party = {.NoItemDefaultMoves = sParty_Trent4}, }, @@ -8954,7 +8954,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TRENT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Trent5), .party = {.NoItemDefaultMoves = sParty_Trent5}, }, @@ -8968,7 +8968,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DEZ & LUKE"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_DezAndLuke), .party = {.NoItemDefaultMoves = sParty_DezAndLuke}, }, @@ -8982,7 +8982,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEA & JED"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_LeaAndJed), .party = {.NoItemDefaultMoves = sParty_LeaAndJed}, }, @@ -8996,7 +8996,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIRA & DAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_KiraAndDan1), .party = {.NoItemDefaultMoves = sParty_KiraAndDan1}, }, @@ -9010,7 +9010,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIRA & DAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_KiraAndDan2), .party = {.NoItemDefaultMoves = sParty_KiraAndDan2}, }, @@ -9024,7 +9024,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIRA & DAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_KiraAndDan3), .party = {.NoItemDefaultMoves = sParty_KiraAndDan3}, }, @@ -9038,7 +9038,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIRA & DAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_KiraAndDan4), .party = {.NoItemDefaultMoves = sParty_KiraAndDan4}, }, @@ -9052,7 +9052,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIRA & DAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_KiraAndDan5), .party = {.NoItemDefaultMoves = sParty_KiraAndDan5}, }, @@ -9066,7 +9066,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHANNA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Johanna), .party = {.NoItemDefaultMoves = sParty_Johanna}, }, @@ -9080,7 +9080,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GERALD"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Gerald), .party = {.NoItemCustomMoves = sParty_Gerald}, }, @@ -9094,7 +9094,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VIVIAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Vivian), .party = {.NoItemCustomMoves = sParty_Vivian}, }, @@ -9108,7 +9108,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DANIELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Danielle), .party = {.NoItemCustomMoves = sParty_Danielle}, }, @@ -9122,7 +9122,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HIDEO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT, .partySize = ARRAY_COUNT(sParty_Hideo), .party = {.NoItemCustomMoves = sParty_Hideo}, }, @@ -9136,7 +9136,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KEIGO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT, .partySize = ARRAY_COUNT(sParty_Keigo), .party = {.NoItemCustomMoves = sParty_Keigo}, }, @@ -9150,7 +9150,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RILEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT, .partySize = ARRAY_COUNT(sParty_Riley), .party = {.NoItemCustomMoves = sParty_Riley}, }, @@ -9164,7 +9164,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLINT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Flint), .party = {.NoItemDefaultMoves = sParty_Flint}, }, @@ -9178,7 +9178,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ASHLEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Ashley), .party = {.NoItemDefaultMoves = sParty_Ashley}, }, @@ -9192,7 +9192,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyMauville), .party = {.NoItemDefaultMoves = sParty_WallyMauville}, }, @@ -9206,7 +9206,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR2), .party = {.NoItemCustomMoves = sParty_WallyVR2}, }, @@ -9220,7 +9220,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR3), .party = {.NoItemCustomMoves = sParty_WallyVR3}, }, @@ -9234,7 +9234,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR4), .party = {.NoItemCustomMoves = sParty_WallyVR4}, }, @@ -9248,7 +9248,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR5), .party = {.NoItemCustomMoves = sParty_WallyVR5}, }, @@ -9262,7 +9262,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanLilycoveMudkip), .party = {.NoItemDefaultMoves = sParty_BrendanLilycoveMudkip}, }, @@ -9276,7 +9276,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanLilycoveTreecko), .party = {.NoItemDefaultMoves = sParty_BrendanLilycoveTreecko}, }, @@ -9290,7 +9290,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanLilycoveTorchic), .party = {.NoItemDefaultMoves = sParty_BrendanLilycoveTorchic}, }, @@ -9304,7 +9304,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayLilycoveMudkip), .party = {.NoItemDefaultMoves = sParty_MayLilycoveMudkip}, }, @@ -9318,7 +9318,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayLilycoveTreecko), .party = {.NoItemDefaultMoves = sParty_MayLilycoveTreecko}, }, @@ -9332,7 +9332,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayLilycoveTorchic), .party = {.NoItemDefaultMoves = sParty_MayLilycoveTorchic}, }, @@ -9346,7 +9346,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JONAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jonah), .party = {.NoItemDefaultMoves = sParty_Jonah}, }, @@ -9360,7 +9360,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HENRY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Henry), .party = {.NoItemDefaultMoves = sParty_Henry}, }, @@ -9374,7 +9374,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROGER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Roger), .party = {.NoItemDefaultMoves = sParty_Roger}, }, @@ -9388,7 +9388,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEXA"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Alexa), .party = {.NoItemDefaultMoves = sParty_Alexa}, }, @@ -9402,7 +9402,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RUBEN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Ruben), .party = {.NoItemDefaultMoves = sParty_Ruben}, }, @@ -9416,7 +9416,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KOJI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Koji1), .party = {.NoItemDefaultMoves = sParty_Koji1}, }, @@ -9430,7 +9430,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WAYNE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Wayne), .party = {.NoItemDefaultMoves = sParty_Wayne}, }, @@ -9444,7 +9444,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AIDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Aidan), .party = {.NoItemDefaultMoves = sParty_Aidan}, }, @@ -9458,7 +9458,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("REED"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Reed), .party = {.NoItemDefaultMoves = sParty_Reed}, }, @@ -9472,7 +9472,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TISHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tisha), .party = {.NoItemDefaultMoves = sParty_Tisha}, }, @@ -9486,7 +9486,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TORI & TIA"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_ToriAndTia), .party = {.NoItemDefaultMoves = sParty_ToriAndTia}, }, @@ -9500,7 +9500,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KIM & IRIS"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_KimAndIris), .party = {.NoItemCustomMoves = sParty_KimAndIris}, }, @@ -9514,7 +9514,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TYRA & IVY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_TyraAndIvy), .party = {.NoItemCustomMoves = sParty_TyraAndIvy}, }, @@ -9528,7 +9528,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MEL & PAUL"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_MelAndPaul), .party = {.NoItemCustomMoves = sParty_MelAndPaul}, }, @@ -9542,7 +9542,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_JohnAndJay1), .party = {.NoItemCustomMoves = sParty_JohnAndJay1}, }, @@ -9556,7 +9556,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_JohnAndJay2), .party = {.NoItemCustomMoves = sParty_JohnAndJay2}, }, @@ -9570,7 +9570,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_JohnAndJay3), .party = {.NoItemCustomMoves = sParty_JohnAndJay3}, }, @@ -9584,7 +9584,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_JohnAndJay4), .party = {.NoItemCustomMoves = sParty_JohnAndJay4}, }, @@ -9598,7 +9598,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_JohnAndJay5), .party = {.NoItemCustomMoves = sParty_JohnAndJay5}, }, @@ -9612,7 +9612,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RELI & IAN"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_ReliAndIan), .party = {.NoItemDefaultMoves = sParty_ReliAndIan}, }, @@ -9626,7 +9626,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LILA & ROY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_LilaAndRoy1), .party = {.NoItemDefaultMoves = sParty_LilaAndRoy1}, }, @@ -9640,7 +9640,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LILA & ROY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_LilaAndRoy2), .party = {.NoItemDefaultMoves = sParty_LilaAndRoy2}, }, @@ -9654,7 +9654,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LILA & ROY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_LilaAndRoy3), .party = {.NoItemDefaultMoves = sParty_LilaAndRoy3}, }, @@ -9668,7 +9668,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LILA & ROY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_LilaAndRoy4), .party = {.NoItemDefaultMoves = sParty_LilaAndRoy4}, }, @@ -9682,7 +9682,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LILA & ROY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_LilaAndRoy5), .party = {.NoItemDefaultMoves = sParty_LilaAndRoy5}, }, @@ -9696,7 +9696,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LISA & RAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_LisaAndRay), .party = {.NoItemDefaultMoves = sParty_LisaAndRay}, }, @@ -9710,7 +9710,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHRIS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Chris), .party = {.NoItemDefaultMoves = sParty_Chris}, }, @@ -9724,7 +9724,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAWSON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dawson), .party = {.ItemDefaultMoves = sParty_Dawson}, }, @@ -9738,7 +9738,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SARAH"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Sarah), .party = {.ItemDefaultMoves = sParty_Sarah}, }, @@ -9752,7 +9752,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARIAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Darian), .party = {.NoItemDefaultMoves = sParty_Darian}, }, @@ -9766,7 +9766,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HAILEY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Hailey), .party = {.NoItemDefaultMoves = sParty_Hailey}, }, @@ -9780,7 +9780,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHANDLER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Chandler), .party = {.NoItemDefaultMoves = sParty_Chandler}, }, @@ -9794,7 +9794,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KALEB"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kaleb), .party = {.ItemDefaultMoves = sParty_Kaleb}, }, @@ -9808,7 +9808,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOSEPH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Joseph), .party = {.NoItemDefaultMoves = sParty_Joseph}, }, @@ -9822,7 +9822,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALYSSA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Alyssa), .party = {.NoItemDefaultMoves = sParty_Alyssa}, }, @@ -9836,7 +9836,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARCOS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Marcos), .party = {.NoItemDefaultMoves = sParty_Marcos}, }, @@ -9850,7 +9850,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RHETT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Rhett), .party = {.NoItemDefaultMoves = sParty_Rhett}, }, @@ -9864,7 +9864,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TYRON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Tyron), .party = {.NoItemDefaultMoves = sParty_Tyron}, }, @@ -9878,7 +9878,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CELINA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Celina), .party = {.NoItemDefaultMoves = sParty_Celina}, }, @@ -9892,7 +9892,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BIANCA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bianca), .party = {.NoItemDefaultMoves = sParty_Bianca}, }, @@ -9906,7 +9906,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HAYDEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Hayden), .party = {.NoItemDefaultMoves = sParty_Hayden}, }, @@ -9920,7 +9920,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SOPHIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Sophie), .party = {.NoItemDefaultMoves = sParty_Sophie}, }, @@ -9934,7 +9934,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("COBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Coby), .party = {.NoItemDefaultMoves = sParty_Coby}, }, @@ -9948,7 +9948,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LAWRENCE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Lawrence), .party = {.NoItemDefaultMoves = sParty_Lawrence}, }, @@ -9962,7 +9962,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WYATT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Wyatt), .party = {.NoItemDefaultMoves = sParty_Wyatt}, }, @@ -9976,7 +9976,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANGELINA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Angelina), .party = {.NoItemDefaultMoves = sParty_Angelina}, }, @@ -9990,7 +9990,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KAI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kai), .party = {.NoItemDefaultMoves = sParty_Kai}, }, @@ -10004,7 +10004,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CHARLOTTE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Charlotte), .party = {.NoItemDefaultMoves = sParty_Charlotte}, }, @@ -10018,7 +10018,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DEANDRE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Deandre), .party = {.NoItemDefaultMoves = sParty_Deandre}, }, @@ -10032,7 +10032,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout1), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout1}, }, @@ -10046,7 +10046,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout2), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout2}, }, @@ -10060,7 +10060,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout3), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout3}, }, @@ -10074,7 +10074,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout4), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout4}, }, @@ -10088,7 +10088,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout5), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout5}, }, @@ -10102,7 +10102,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout6), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout6}, }, @@ -10116,7 +10116,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout7), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout7}, }, @@ -10130,7 +10130,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout8), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout8}, }, @@ -10144,7 +10144,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout9), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout9}, }, @@ -10158,7 +10158,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout10), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout10}, }, @@ -10172,7 +10172,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout11), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout11}, }, @@ -10186,7 +10186,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout12), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout12}, }, @@ -10200,7 +10200,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout13), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout13}, }, @@ -10214,7 +10214,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout14), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout14}, }, @@ -10228,7 +10228,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout15), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout15}, }, @@ -10242,7 +10242,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRUNT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_GruntMagmaHideout16), .party = {.NoItemDefaultMoves = sParty_GruntMagmaHideout16}, }, @@ -10256,7 +10256,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TABITHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_TabithaMagmaHideout), .party = {.NoItemDefaultMoves = sParty_TabithaMagmaHideout}, }, @@ -10270,7 +10270,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARCY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Darcy), .party = {.NoItemDefaultMoves = sParty_Darcy}, }, @@ -10284,7 +10284,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAXIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MaxieMossdeep), .party = {.NoItemDefaultMoves = sParty_MaxieMossdeep}, }, @@ -10298,7 +10298,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PETE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Pete), .party = {.NoItemDefaultMoves = sParty_Pete}, }, @@ -10312,7 +10312,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ISABELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Isabelle), .party = {.NoItemDefaultMoves = sParty_Isabelle}, }, @@ -10326,7 +10326,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANDRES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Andres1), .party = {.NoItemDefaultMoves = sParty_Andres1}, }, @@ -10340,7 +10340,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOSUE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Josue), .party = {.NoItemDefaultMoves = sParty_Josue}, }, @@ -10354,7 +10354,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAMRON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Camron), .party = {.NoItemDefaultMoves = sParty_Camron}, }, @@ -10368,7 +10368,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CORY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cory1), .party = {.NoItemDefaultMoves = sParty_Cory1}, }, @@ -10382,7 +10382,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAROLINA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Carolina), .party = {.NoItemDefaultMoves = sParty_Carolina}, }, @@ -10396,7 +10396,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ELIJAH"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Elijah), .party = {.NoItemDefaultMoves = sParty_Elijah}, }, @@ -10410,7 +10410,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CELIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Celia), .party = {.NoItemDefaultMoves = sParty_Celia}, }, @@ -10424,7 +10424,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRYAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bryan), .party = {.NoItemDefaultMoves = sParty_Bryan}, }, @@ -10438,7 +10438,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRANDEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Branden), .party = {.NoItemDefaultMoves = sParty_Branden}, }, @@ -10452,7 +10452,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRYANT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Bryant), .party = {.NoItemDefaultMoves = sParty_Bryant}, }, @@ -10466,7 +10466,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHAYLA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Shayla), .party = {.NoItemDefaultMoves = sParty_Shayla}, }, @@ -10480,7 +10480,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KYRA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Kyra), .party = {.NoItemDefaultMoves = sParty_Kyra}, }, @@ -10494,7 +10494,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAIDEN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Jaiden), .party = {.NoItemDefaultMoves = sParty_Jaiden}, }, @@ -10508,7 +10508,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALIX"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Alix), .party = {.NoItemDefaultMoves = sParty_Alix}, }, @@ -10522,7 +10522,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HELENE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Helene), .party = {.NoItemDefaultMoves = sParty_Helene}, }, @@ -10536,7 +10536,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARLENE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Marlene), .party = {.NoItemDefaultMoves = sParty_Marlene}, }, @@ -10550,7 +10550,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DEVAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Devan), .party = {.NoItemDefaultMoves = sParty_Devan}, }, @@ -10564,7 +10564,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHNSON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Johnson), .party = {.NoItemDefaultMoves = sParty_Johnson}, }, @@ -10578,7 +10578,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MELINA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Melina), .party = {.NoItemDefaultMoves = sParty_Melina}, }, @@ -10592,7 +10592,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRANDI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Brandi), .party = {.NoItemDefaultMoves = sParty_Brandi}, }, @@ -10606,7 +10606,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("AISHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Aisha), .party = {.NoItemDefaultMoves = sParty_Aisha}, }, @@ -10620,7 +10620,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAKAYLA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Makayla), .party = {.NoItemDefaultMoves = sParty_Makayla}, }, @@ -10634,7 +10634,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FABIAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Fabian), .party = {.NoItemDefaultMoves = sParty_Fabian}, }, @@ -10648,7 +10648,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DAYTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Dayton), .party = {.NoItemDefaultMoves = sParty_Dayton}, }, @@ -10662,7 +10662,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RACHEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Rachel), .party = {.NoItemDefaultMoves = sParty_Rachel}, }, @@ -10676,7 +10676,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEONEL"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Leonel), .party = {.NoItemCustomMoves = sParty_Leonel}, }, @@ -10690,7 +10690,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CALLIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Callie), .party = {.NoItemDefaultMoves = sParty_Callie}, }, @@ -10704,7 +10704,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CALE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cale), .party = {.NoItemDefaultMoves = sParty_Cale}, }, @@ -10718,7 +10718,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MYLES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Myles), .party = {.NoItemDefaultMoves = sParty_Myles}, }, @@ -10732,7 +10732,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAT"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Pat), .party = {.NoItemDefaultMoves = sParty_Pat}, }, @@ -10746,7 +10746,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin1), .party = {.NoItemDefaultMoves = sParty_Cristin1}, }, @@ -10760,7 +10760,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRustboroTreecko), .party = {.NoItemDefaultMoves = sParty_MayRustboroTreecko}, }, @@ -10774,7 +10774,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRustboroTorchic), .party = {.NoItemDefaultMoves = sParty_MayRustboroTorchic}, }, @@ -10788,7 +10788,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne2), .party = {.ItemCustomMoves = sParty_Roxanne2}, }, @@ -10802,7 +10802,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne3), .party = {.ItemCustomMoves = sParty_Roxanne3}, }, @@ -10816,7 +10816,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne4), .party = {.ItemCustomMoves = sParty_Roxanne4}, }, @@ -10830,7 +10830,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne5), .party = {.ItemCustomMoves = sParty_Roxanne5}, }, @@ -10844,7 +10844,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly2), .party = {.ItemCustomMoves = sParty_Brawly2}, }, @@ -10858,7 +10858,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly3), .party = {.ItemCustomMoves = sParty_Brawly3}, }, @@ -10872,7 +10872,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly4), .party = {.ItemCustomMoves = sParty_Brawly4}, }, @@ -10886,7 +10886,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly5), .party = {.ItemCustomMoves = sParty_Brawly5}, }, @@ -10900,7 +10900,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson2), .party = {.ItemCustomMoves = sParty_Wattson2}, }, @@ -10914,7 +10914,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson3), .party = {.ItemCustomMoves = sParty_Wattson3}, }, @@ -10928,7 +10928,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson4), .party = {.ItemCustomMoves = sParty_Wattson4}, }, @@ -10942,7 +10942,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson5), .party = {.ItemCustomMoves = sParty_Wattson5}, }, @@ -10956,7 +10956,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery2), .party = {.ItemCustomMoves = sParty_Flannery2}, }, @@ -10970,7 +10970,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery3), .party = {.ItemCustomMoves = sParty_Flannery3}, }, @@ -10984,7 +10984,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery4), .party = {.ItemCustomMoves = sParty_Flannery4}, }, @@ -10998,7 +10998,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery5), .party = {.ItemCustomMoves = sParty_Flannery5}, }, @@ -11012,7 +11012,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman2), .party = {.ItemCustomMoves = sParty_Norman2}, }, @@ -11026,7 +11026,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman3), .party = {.ItemCustomMoves = sParty_Norman3}, }, @@ -11040,7 +11040,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman4), .party = {.ItemCustomMoves = sParty_Norman4}, }, @@ -11054,7 +11054,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman5), .party = {.ItemCustomMoves = sParty_Norman5}, }, @@ -11068,7 +11068,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona2), .party = {.ItemCustomMoves = sParty_Winona2}, }, @@ -11082,7 +11082,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona3), .party = {.ItemCustomMoves = sParty_Winona3}, }, @@ -11096,7 +11096,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona4), .party = {.ItemCustomMoves = sParty_Winona4}, }, @@ -11110,7 +11110,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona5), .party = {.ItemCustomMoves = sParty_Winona5}, }, @@ -11124,7 +11124,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza2), .party = {.ItemCustomMoves = sParty_TateAndLiza2}, }, @@ -11138,7 +11138,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza3), .party = {.ItemCustomMoves = sParty_TateAndLiza3}, }, @@ -11152,7 +11152,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza4), .party = {.ItemCustomMoves = sParty_TateAndLiza4}, }, @@ -11166,7 +11166,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza5), .party = {.ItemCustomMoves = sParty_TateAndLiza5}, }, @@ -11180,7 +11180,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan2), .party = {.ItemCustomMoves = sParty_Juan2}, }, @@ -11194,7 +11194,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan3), .party = {.ItemCustomMoves = sParty_Juan3}, }, @@ -11208,7 +11208,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan4), .party = {.ItemCustomMoves = sParty_Juan4}, }, @@ -11222,7 +11222,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan5), .party = {.ItemCustomMoves = sParty_Juan5}, }, @@ -11236,7 +11236,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANGELO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Angelo), .party = {.ItemCustomMoves = sParty_Angelo}, }, @@ -11250,7 +11250,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARIUS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Darius), .party = {.NoItemDefaultMoves = sParty_Darius}, }, @@ -11264,7 +11264,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("STEVEN"), .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, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Steven), .party = {.ItemCustomMoves = sParty_Steven}, }, @@ -11278,7 +11278,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANABEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Anabel), .party = {.NoItemDefaultMoves = sParty_Anabel}, }, @@ -11292,7 +11292,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TUCKER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Tucker), .party = {.NoItemDefaultMoves = sParty_Tucker}, }, @@ -11306,7 +11306,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SPENSER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Spenser), .party = {.NoItemDefaultMoves = sParty_Spenser}, }, @@ -11320,7 +11320,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRETA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Greta), .party = {.NoItemDefaultMoves = sParty_Greta}, }, @@ -11334,7 +11334,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOLAND"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Noland), .party = {.NoItemDefaultMoves = sParty_Noland}, }, @@ -11348,7 +11348,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUCY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Lucy), .party = {.NoItemDefaultMoves = sParty_Lucy}, }, @@ -11362,7 +11362,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRANDON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brandon), .party = {.NoItemDefaultMoves = sParty_Brandon}, }, @@ -11376,7 +11376,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANDRES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Andres2), .party = {.NoItemDefaultMoves = sParty_Andres2}, }, @@ -11390,7 +11390,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANDRES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Andres3), .party = {.NoItemDefaultMoves = sParty_Andres3}, }, @@ -11404,7 +11404,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANDRES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Andres4), .party = {.NoItemDefaultMoves = sParty_Andres4}, }, @@ -11418,7 +11418,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANDRES"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Andres5), .party = {.NoItemDefaultMoves = sParty_Andres5}, }, @@ -11432,7 +11432,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CORY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cory2), .party = {.NoItemDefaultMoves = sParty_Cory2}, }, @@ -11446,7 +11446,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CORY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cory3), .party = {.NoItemDefaultMoves = sParty_Cory3}, }, @@ -11460,7 +11460,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CORY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cory4), .party = {.NoItemDefaultMoves = sParty_Cory4}, }, @@ -11474,7 +11474,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CORY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Cory5), .party = {.NoItemDefaultMoves = sParty_Cory5}, }, @@ -11488,7 +11488,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PABLO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Pablo2), .party = {.NoItemDefaultMoves = sParty_Pablo2}, }, @@ -11502,7 +11502,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PABLO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Pablo3), .party = {.NoItemDefaultMoves = sParty_Pablo3}, }, @@ -11516,7 +11516,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PABLO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Pablo4), .party = {.NoItemDefaultMoves = sParty_Pablo4}, }, @@ -11530,7 +11530,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PABLO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Pablo5), .party = {.NoItemDefaultMoves = sParty_Pablo5}, }, @@ -11544,7 +11544,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KOJI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Koji2), .party = {.NoItemDefaultMoves = sParty_Koji2}, }, @@ -11558,7 +11558,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KOJI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Koji3), .party = {.NoItemDefaultMoves = sParty_Koji3}, }, @@ -11572,7 +11572,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KOJI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Koji4), .party = {.NoItemDefaultMoves = sParty_Koji4}, }, @@ -11586,7 +11586,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KOJI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Koji5), .party = {.NoItemDefaultMoves = sParty_Koji5}, }, @@ -11600,7 +11600,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin2), .party = {.NoItemDefaultMoves = sParty_Cristin2}, }, @@ -11614,7 +11614,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin3), .party = {.NoItemDefaultMoves = sParty_Cristin3}, }, @@ -11628,7 +11628,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin4), .party = {.NoItemDefaultMoves = sParty_Cristin4}, }, @@ -11642,7 +11642,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin5), .party = {.NoItemDefaultMoves = sParty_Cristin5}, }, @@ -11656,7 +11656,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FERNANDO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Fernando2), .party = {.NoItemDefaultMoves = sParty_Fernando2}, }, @@ -11670,7 +11670,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FERNANDO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Fernando3), .party = {.NoItemDefaultMoves = sParty_Fernando3}, }, @@ -11684,7 +11684,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FERNANDO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Fernando4), .party = {.NoItemDefaultMoves = sParty_Fernando4}, }, @@ -11698,7 +11698,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FERNANDO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Fernando5), .party = {.NoItemDefaultMoves = sParty_Fernando5}, }, @@ -11712,7 +11712,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer2), .party = {.NoItemDefaultMoves = sParty_Sawyer2}, }, @@ -11726,7 +11726,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer3), .party = {.NoItemDefaultMoves = sParty_Sawyer3}, }, @@ -11740,7 +11740,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer4), .party = {.NoItemDefaultMoves = sParty_Sawyer4}, }, @@ -11754,7 +11754,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer5), .party = {.NoItemDefaultMoves = sParty_Sawyer5}, }, @@ -11768,7 +11768,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABRIELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Gabrielle2), .party = {.NoItemDefaultMoves = sParty_Gabrielle2}, }, @@ -11782,7 +11782,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABRIELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Gabrielle3), .party = {.NoItemDefaultMoves = sParty_Gabrielle3}, }, @@ -11796,7 +11796,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABRIELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Gabrielle4), .party = {.NoItemDefaultMoves = sParty_Gabrielle4}, }, @@ -11810,7 +11810,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GABRIELLE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Gabrielle5), .party = {.NoItemDefaultMoves = sParty_Gabrielle5}, }, @@ -11824,7 +11824,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("THALIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Thalia2), .party = {.NoItemDefaultMoves = sParty_Thalia2}, }, @@ -11838,7 +11838,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("THALIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Thalia3), .party = {.NoItemDefaultMoves = sParty_Thalia3}, }, @@ -11852,7 +11852,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("THALIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Thalia4), .party = {.NoItemDefaultMoves = sParty_Thalia4}, }, @@ -11866,7 +11866,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("THALIA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_SCRIPT_CHECK_BAD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE, .partySize = ARRAY_COUNT(sParty_Thalia5), .party = {.NoItemDefaultMoves = sParty_Thalia5}, }, diff --git a/src/trainer_hill.c b/src/trainer_hill.c index 18d56723cf..043522aee1 100644 --- a/src/trainer_hill.c +++ b/src/trainer_hill.c @@ -897,7 +897,7 @@ void FillHillTrainersParties(void) // hill trainers. u32 GetTrainerHillAIFlags(void) { - return (AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_CHECK_VIABILITY); + return (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); } u8 GetTrainerEncounterMusicIdInTrainerHill(u16 trainerId) From 916d0416e3f67de5c1ffb9b6301f5027d0383744 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 15 Dec 2020 21:57:33 -0700 Subject: [PATCH 05/36] outline AI_CheckGoodMove --- include/battle_ai_script_commands.h | 9 - include/battle_ai_util.h | 19 +- include/constants/battle_ai.h | 3 +- src/battle_ai_script_commands.c | 761 ++++++++++++++++++++-------- src/battle_ai_switch_items.c | 1 + src/battle_ai_util.c | 262 +++++++--- src/battle_factory.c | 4 +- src/battle_main.c | 1 + src/battle_script_commands.c | 1 + src/battle_util.c | 1 + src/data/trainers.h | 358 ++++++------- src/trainer_hill.c | 2 +- 12 files changed, 961 insertions(+), 461 deletions(-) diff --git a/include/battle_ai_script_commands.h b/include/battle_ai_script_commands.h index eb57d613f4..75d96ff52d 100644 --- a/include/battle_ai_script_commands.h +++ b/include/battle_ai_script_commands.h @@ -7,9 +7,6 @@ #define AI_CHOICE_WATCH 5 #define AI_CHOICE_SWITCH 7 -s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef); -s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon); -u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); void BattleAI_SetupItems(void); void BattleAI_SetupFlags(void); void BattleAI_SetupAIData(u8 defaultScoreMoves); @@ -17,12 +14,6 @@ u8 BattleAI_ChooseMoveOrAction(void); bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler); bool32 IsBattlerAIControlled(u32 battlerId); void ClearBattlerMoveHistory(u8 battlerId); -void RecordLastUsedMoveBy(u32 battlerId, u32 move); -void RecordKnownMove(u8 battlerId, u32 move); -void RecordAbilityBattle(u8 battlerId, u16 abilityId); -void ClearBattlerAbilityHistory(u8 battlerId); -void RecordItemEffectBattle(u8 battlerId, u8 itemEffect); -void ClearBattlerItemEffectHistory(u8 battlerId); extern u8 sBattler_AI; diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 5d778ef3fd..134fefc706 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -24,14 +24,13 @@ u32 GetHealthPercentage(u8 battler); bool32 IsBattlerTrapped(u8 battler, bool8 switching); bool32 IsBattlerFaster(u8 battler); bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk); +bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod); s32 AI_GetAbility(u32 battlerId); u16 AI_GetHoldEffect(u32 battlerId); u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move); bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move); bool32 AI_WeatherHasEffect(void); bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index); -s32 CountUsablePartyMons(u8 battlerId); -bool32 IsPartyFullyHealedExceptBattler(u8 battler); bool32 AI_IsBattlerGrounded(u8 battlerId); bool32 BattlerHasDamagingMove(u8 battlerId); bool32 BattlerHasSecondaryDamage(u8 battlerId); @@ -39,6 +38,7 @@ bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability); bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move); bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex); u16 GetBattlerSideSpeedAverage(u8 battler); +bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage); // stat stage checks bool32 AnyStatIsRaised(u8 battlerId); @@ -51,13 +51,15 @@ u32 CountNegativeStatStages(u8 battlerId); bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability); // move checks -u8 GetMovePowerResult(u16 move); +s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef); +u8 GetMoveDamageResult(u16 move); u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); u8 AI_GetMoveEffectiveness(u16 move); u16 *GetMovesArray(u32 battler); bool32 IsConfusionMoveEffect(u16 moveEffect); bool32 HasMoveWithSplit(u32 battler, u32 split); bool32 HasMoveWithType(u32 battler, u8 type); +bool32 HasMoveEffect(u32 battlerId, u16 moveEffect); bool32 TestMoveFlagsInMoveset(u8 battler, u32 flags); bool32 IsAromaVeilProtectedMove(u16 move); bool32 IsNonVolatileStatusMoveEffect(u16 moveEffect); @@ -70,13 +72,13 @@ bool32 MoveRequiresRecharging(u16 move); bool32 IsInstructBannedMove(u16 move); // status checks -bool32 AI_ShouldPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); -bool32 AI_ShouldPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); +bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); +bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); -bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof); bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGender, u8 defGender); +bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof); // partner logic u16 GetAllyChosenMove(void); @@ -91,4 +93,9 @@ bool32 PartnerMoveIs(u8 battlerAtkPartner, u16 partnerMove, u16 moveCheck); bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove); bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove); +// party logic +s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon); +s32 CountUsablePartyMons(u8 battlerId); +bool32 IsPartyFullyHealedExceptBattler(u8 battler); + #endif //GUARD_BATTLE_AI_UTIL_H \ No newline at end of file diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index dd29f20f2e..5e97ab6aa9 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -38,7 +38,7 @@ // 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_CHECK_GOOD_MOVE (1 << 2) // was AI_SCRIPT_CHECK_VIABILITY #define AI_FLAG_SETUP_FIRST_TURN (1 << 3) #define AI_FLAG_RISKY (1 << 4) #define AI_FLAG_PREFER_STRONGEST_MOVE (1 << 5) @@ -49,6 +49,7 @@ #define AI_FLAG_NEGATE_AWARE (1 << 9) // AI is aware of negating effects like wonder room, mold breaker, etc (eg. smart trainers). TODO unfinished #define AI_FLAG_HELP_PARTNER (1 << 10) // AI can try to help partner. If not set, will tend not to target partner #define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc +#define AI_FLAG_PREFER_STATUS_MOVES (1 << 12) // AI gets a score bonus for status moves. Should be combined with AI_FLAG_CHECK_BAD_MOVE to prevent using only status moves // 'other' ai logic flags #define AI_FLAG_ROAMING (1 << 29) diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 5144e5ce88..033db8e79d 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -27,18 +27,6 @@ #define AI_ACTION_UNK7 0x0040 #define AI_ACTION_UNK8 0x0080 -#define RETURN_SCORE_MINUS(a) \ -{ \ - score -= a; \ - return score; \ -} -#define RETURN_SCORE_PLUS(a) \ -{ \ - score += a; \ - return score; \ -} - - // AI states enum { @@ -194,33 +182,33 @@ EWRAM_DATA u8 sBattler_AI = 0; // const rom data typedef void (*BattleAICmdFunc)(void); -static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); -static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 (*const sBattleAiFuncTable[])(u8, u8, u16, u8) = +static u8 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = { [0] = AI_CheckBadMove, // AI_FLAG_CHECK_BAD_MOVE [1] = AI_TryToFaint, // AI_FLAG_TRY_TO_FAINT - [2] = AI_CheckViability, // AI_FLAG_CHECK_VIABILITY + [2] = AI_CheckGoodMove, // AI_FLAG_CHECK_GOOD_MOVE [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 + [7] = AI_DoubleBattle, // AI_FLAG_DOUBLE_BATTLE [8] = AI_HPAware, // AI_FLAG_HP_AWARE - [9] = NULL, // Unused - [10] = NULL, // Unused - [11] = NULL, // Unused + [9] = NULL, // AI_FLAG_NEGATE_AWARE + [10] = NULL, // AI_FLAG_HELP_PARTNER + [11] = NULL, // AI_FLAG_WILL_SUICIDE [12] = NULL, // Unused [13] = NULL, // Unused [14] = NULL, // Unused @@ -237,7 +225,7 @@ static u8 (*const sBattleAiFuncTable[])(u8, u8, u16, u8) = [25] = NULL, // Unused [26] = NULL, // Unused [27] = NULL, // Unused - [28] = NULL, // Unused + [28] = NULL, // Unused [29] = AI_Roaming, // AI_FLAG_ROAMING [30] = AI_Safari, // AI_FLAG_SAFARI [31] = AI_FirstBattle, // AI_FLAG_FIRST_BATTLE @@ -410,7 +398,7 @@ void BattleAI_SetupFlags(void) else if (gBattleTypeFlags & BATTLE_TYPE_FACTORY) AI_THINKING_STRUCT->aiFlags = GetAiScriptsInBattleFactory(); else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE)) - AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT; + AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_TRY_TO_FAINT; else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags | gTrainers[gTrainerBattleOpponent_B].aiFlags; else @@ -553,13 +541,13 @@ static u8 ChooseMoveOrAction_Singles(void) && !(gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) && !(gStatuses3[gActiveBattler] & STATUS3_ROOTED) && !(gBattleTypeFlags & (BATTLE_TYPE_ARENA | BATTLE_TYPE_PALACE)) - && AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY | AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_PREFER_BATON_PASS)) + && AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_GOOD_MOVE | 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[sBattler_AI].species) >= 310 // Mon is not weak. && gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2) { - s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY) ? 95 : 93; + s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_GOOD_MOVE) ? 95 : 93; for (i = 0; i < MAX_MON_MOVES; i++) { if (AI_THINKING_STRUCT->score[i] > cap) @@ -751,16 +739,14 @@ static void BattleAI_DoAIProcessing(void) AI_THINKING_STRUCT->aiState++; break; case AIState_Processing: - if (AI_THINKING_STRUCT->moveConsidered != MOVE_NONE - && AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] > 0) - { - if (AI_THINKING_STRUCT->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable) - && sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId] != NULL) - { - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId](gBattlerAttacker, - gBattlerTarget, - AI_THINKING_STRUCT->moveConsidered, - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex]); //Run AI script + if (AI_THINKING_STRUCT->moveConsidered != MOVE_NONE) + { + if (AI_THINKING_STRUCT->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable) && sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId] != NULL) + { + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] += sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId](sBattler_AI, + gBattlerTarget, AI_THINKING_STRUCT->moveConsidered, AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex]); + if (AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] < 0) + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; // limit to 0 } } else @@ -768,6 +754,7 @@ static void BattleAI_DoAIProcessing(void) 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++; @@ -784,82 +771,6 @@ static void BattleAI_DoAIProcessing(void) } } -static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef) -{ - bool32 isCrit; - - switch (CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE)) - { - case -1: - case 0: - default: - isCrit = FALSE; - break; - case 1: - if (gBattleMoves[move].flags & FLAG_HIGH_CRIT && (Random() % 5 == 0)) - isCrit = TRUE; - else - isCrit = FALSE; - break; - case 2: - if (gBattleMoves[move].flags & FLAG_HIGH_CRIT && (Random() % 2 == 0)) - isCrit = TRUE; - else if (!(gBattleMoves[move].flags & FLAG_HIGH_CRIT) && (Random() % 4) == 0) - isCrit = TRUE; - else - isCrit = FALSE; - break; - case -2: - case 3: - case 4: - isCrit = TRUE; - break; - } - - return isCrit; -} - -s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) -{ - s32 dmg, moveType; - - SaveBattlerData(battlerAtk); - SaveBattlerData(battlerDef); - - SetBattlerData(battlerAtk); - SetBattlerData(battlerDef); - - gBattleStruct->dynamicMoveType = 0; - SetTypeBeforeUsingMove(move, battlerAtk); - GET_MOVE_TYPE(move, moveType); - dmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, AI_GetIfCrit(move, battlerAtk, battlerDef), FALSE, FALSE); - - RestoreBattlerData(battlerAtk); - RestoreBattlerData(battlerDef); - - return dmg; -} - -s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon) -{ - s32 dmg; - u32 i; - struct BattlePokemon *battleMons = Alloc(sizeof(struct BattlePokemon) * MAX_BATTLERS_COUNT); - - for (i = 0; i < MAX_BATTLERS_COUNT; i++) - battleMons[i] = gBattleMons[i]; - - PokemonToBattleMon(mon, &gBattleMons[battlerAtk]); - dmg = AI_CalcDamage(move, battlerAtk, battlerDef); - - for (i = 0; i < MAX_BATTLERS_COUNT; i++) - gBattleMons[i] = battleMons[i]; - - Free(battleMons); - - return dmg; -} - static void Cmd_if_random_less_than(void) { u16 random = Random(); @@ -1287,7 +1198,7 @@ static void Cmd_get_considered_move_power(void) static void Cmd_get_how_powerful_move_is(void) { - // GetMovePowerResult + // GetMoveDamageResult } static void Cmd_get_last_used_battler_move(void) @@ -2435,8 +2346,8 @@ static void Cmd_if_has_move_with_accuracy_lt(void) // AI Functions -static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) -{ +static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +{ // attacker data u16 atkAbility = AI_GetAbility(battlerAtk); u8 atkHoldEffect = AI_GetHoldEffect(battlerAtk); @@ -2455,7 +2366,6 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco u8 battlerDefPartner = BATTLE_PARTNER(battlerDef); u16 defPartnerAbility = AI_GetAbility(battlerDefPartner); // move data - s16 score = originalScore; u16 moveEffect = gBattleMoves[move].effect; u8 moveType = gBattleMoves[move].type; u8 moveTarget = gBattleMoves[move].target; @@ -2463,7 +2373,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco u8 effectiveness = AI_GetMoveEffectiveness(move); if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HELP_PARTNER) && targetSameSide) - return originalScore; // don't consider ally presence + return score; // don't consider ally presence if (!(gBattleMoves[move].target & MOVE_TARGET_USER)) { @@ -2474,7 +2384,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco if ((B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS)) || defAbility == ABILITY_OVERCOAT || GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_SAFETY_GOOGLES) - RETURN_SCORE_MINUS(10); + score -= 10; } // check ground immunities @@ -2486,12 +2396,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco || (gStatuses3[battlerDef] & (STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS))) && move != MOVE_THOUSAND_ARROWS) { - RETURN_SCORE_MINUS(10); + score -= 10; } // check if negates type if (effectiveness == AI_EFFECTIVENESS_x0) - RETURN_SCORE_MINUS(20); + score -= 20; // target ability checks if (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) @@ -2502,17 +2412,17 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco case ABILITY_MOTOR_DRIVE: case ABILITY_LIGHTNING_ROD: if (moveType == TYPE_ELECTRIC && !IsTargetingPartner(battlerAtk, battlerDef)) - RETURN_SCORE_MINUS(20); + score -= 20; break; case ABILITY_WATER_ABSORB: case ABILITY_DRY_SKIN: case ABILITY_STORM_DRAIN: if (moveType == TYPE_WATER && !IsTargetingPartner(battlerAtk, battlerDef)) - RETURN_SCORE_MINUS(20); + score -= 20; break; case ABILITY_FLASH_FIRE: if (moveType == TYPE_FIRE && !IsTargetingPartner(battlerAtk, battlerDef)) - RETURN_SCORE_MINUS(20); + score -= 20; break; case ABILITY_WONDER_GUARD: if (effectiveness != AI_EFFECTIVENESS_x2 && effectiveness != AI_EFFECTIVENESS_x4) @@ -2520,82 +2430,82 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco break; case ABILITY_SAP_SIPPER: if (moveType == TYPE_GRASS && !IsTargetingPartner(battlerAtk, battlerDef)) - RETURN_SCORE_MINUS(20); + score -= 20; break; case ABILITY_JUSTIFIED: if (moveType == TYPE_DARK && !IS_MOVE_STATUS(move) && !IsTargetingPartner(battlerAtk, battlerDef)) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_RATTLED: if (!IS_MOVE_STATUS(move) && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) && !IsTargetingPartner(battlerAtk, battlerDef)) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_SOUNDPROOF: if (TestMoveFlags(move, FLAG_SOUND)) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_BULLETPROOF: if (TestMoveFlags(move, FLAG_BALLISTIC)) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_DAZZLING: case ABILITY_QUEENLY_MAJESTY: if (atkPriority > 0) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_AROMA_VEIL: if (IsAromaVeilProtectedMove(move)) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_SWEET_VEIL: if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_FLOWER_VEIL: if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) && (IsNonVolatileStatusMoveEffect(moveEffect) || IsStatLoweringMoveEffect(moveEffect))) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_MAGIC_BOUNCE: if (TestMoveFlags(move, FLAG_MAGICCOAT_AFFECTED)) - RETURN_SCORE_MINUS(20); + score -= 20; break; case ABILITY_CONTRARY: if (IsStatLoweringMoveEffect(moveEffect) && !IsTargetingPartner(battlerAtk, battlerDef)) - RETURN_SCORE_MINUS(20); + score -= 20; break; case ABILITY_CLEAR_BODY: //case ABILITY_FULL_METAL_BODY: // maybe? case ABILITY_WHITE_SMOKE: if (IsStatLoweringMoveEffect(moveEffect)) - RETURN_SCORE_MINUS(10); + score -= 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); + score -= 10; break; case ABILITY_KEEN_EYE: if (moveEffect == EFFECT_ACCURACY_DOWN || moveEffect == EFFECT_ACCURACY_DOWN_2) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_BIG_PECKS: if (moveEffect == EFFECT_DEFENSE_DOWN || moveEffect == EFFECT_DEFENSE_DOWN_2) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_DEFIANT: case ABILITY_COMPETITIVE: if (IsStatLoweringMoveEffect(moveEffect) && !IsTargetingPartner(battlerAtk, battlerDef)) - RETURN_SCORE_MINUS(8); + score -= 8; break; case ABILITY_COMATOSE: if (IsNonVolatileStatusMoveEffect(moveEffect)) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_SHIELDS_DOWN: if (IsShieldsDownProtected(battlerAtk) && IsNonVolatileStatusMoveEffect(moveEffect)) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_WONDER_SKIN: if (IS_MOVE_STATUS(move)) @@ -2605,7 +2515,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco if (AI_WeatherHasEffect() && (gBattleWeather & WEATHER_SUN_ANY) && defHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA && IsNonVolatileStatusMoveEffect(moveEffect)) - RETURN_SCORE_MINUS(10); + score -= 10; break; } // def ability checks @@ -2616,32 +2526,32 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco { case ABILITY_LIGHTNING_ROD: if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(move, atkAbility)) - RETURN_SCORE_MINUS(20); + score -= 20; break; case ABILITY_STORM_DRAIN: if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(move, atkAbility)) - RETURN_SCORE_MINUS(20); + score -= 20; break; case ABILITY_MAGIC_BOUNCE: if (TestMoveFlags(move, FLAG_MAGICCOAT_AFFECTED) && moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD)) - RETURN_SCORE_MINUS(20); + score -= 20; break; case ABILITY_SWEET_VEIL: if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_FLOWER_VEIL: if ((IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS)) && (IsNonVolatileStatusMoveEffect(moveEffect) || IsStatLoweringMoveEffect(moveEffect))) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_AROMA_VEIL: if (IsAromaVeilProtectedMove(move)) - RETURN_SCORE_MINUS(10); + score -= 10; break; case ABILITY_DAZZLING: case ABILITY_QUEENLY_MAJESTY: if (atkPriority > 0) - RETURN_SCORE_MINUS(10); + score -= 10; break; } } // def partner ability checks @@ -2650,24 +2560,24 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco #if B_PRANKSTER < GEN_7 if (atkAbility == ABILITY_PRANKSTER && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) && IS_MOVE_STATUS(move) && !(moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER))) - RETURN_SCORE_MINUS(10); + score -= 10; #endif // terrain effect checks if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) { if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) - RETURN_SCORE_MINUS(10); + score -= 10; } if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) { if (IsNonVolatileStatusMoveEffect(moveEffect) || IsConfusionMoveEffect(moveEffect)) - RETURN_SCORE_MINUS(10); + score -= 10; } if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) { if (atkPriority > 0) - RETURN_SCORE_MINUS(10); + score -= 10; } } // end check MOVE_TARGET_USER // the following checks apply to any target (including user) @@ -2690,7 +2600,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco case EFFECT_SLEEP: if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) score -= 10; - else if (!AI_ShouldPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + else if (!AI_CanPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) score -= 10; break; case EFFECT_ABSORB: @@ -3017,12 +2927,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) - RETURN_SCORE_MINUS(10); // Don't want to reset our boosted stats + 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[battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) - RETURN_SCORE_MINUS(10); //Don't want to reset enemy lowered stats + score -= 10; //Don't want to reset enemy lowered stats } } break; @@ -3034,7 +2944,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco break; case EFFECT_ROAR: if (DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) - RETURN_SCORE_MINUS(10); // don't scare away pokemon twice + score -= 10; // don't scare away pokemon twice //Don't blow out a Pokemon that'll faint soon or is taking a a lot of secondary damage if (GetHealthPercentage(battlerDef) < 10 && BattlerHasSecondaryDamage(battlerDef)) @@ -3084,7 +2994,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco //fallthrough case EFFECT_POISON: case EFFECT_TOXIC: - if (!AI_ShouldPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (!AI_CanPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) score -= 10; else if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) score -= 10; @@ -3599,12 +3509,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) - RETURN_SCORE_MINUS(10); // Don't want to reset our boosted stats + 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[battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) - RETURN_SCORE_MINUS(10); //Don't want to copy enemy lowered stats + score -= 10; //Don't want to copy enemy lowered stats } } break; @@ -3720,7 +3630,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco // case EFFECT_SHELL_TRAP: // case EFFECT_BEAK_BLAST: case EFFECT_NATURE_POWER: - return AI_CheckBadMove(battlerAtk, battlerDef, GetNaturePowerMove(), originalScore); + return AI_CheckBadMove(battlerAtk, battlerDef, GetNaturePowerMove(), score); case EFFECT_CHARGE: if (gStatuses3[battlerAtk] & STATUS3_CHARGED_UP) { @@ -3805,7 +3715,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco case EFFECT_YAWN: if (gStatuses3[battlerDef] & STATUS3_YAWN) score -= 10; - else if (!AI_ShouldPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + else if (!AI_CanPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) score -= 10; break; case EFFECT_KNOCK_OFF: @@ -3856,13 +3766,13 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco score -= 10; break; case EFFECT_PSYCHO_SHIFT: - if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_ShouldPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_CanPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) score -= 10; else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && !AI_CanBurn(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) score -= 10; else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, defAbility, move, partnerMove)) score -= 10; - else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_ShouldPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_CanPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) score -= 10; else score -= 10; @@ -4152,11 +4062,11 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco score -= 10; break; case MOVE_EFFECT_POISON: - if (!AI_ShouldPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (!AI_CanPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) score -= 10; break; case MOVE_EFFECT_TOXIC: - if (!AI_ShouldPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (!AI_CanPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) score -= 10; break; case MOVE_EFFECT_FREEZE: @@ -4390,7 +4300,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) score -= 15; - if (effectiveness < AI_EFFECTIVENESS_x1) + if (effectiveness < AI_EFFECTIVENESS_x1 || GetMoveDamageResult(move) <= MOVE_POWER_WEAK) score -= 4; } @@ -4400,23 +4310,19 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalSco && IS_MOVE_STATUS(move)) score -= 10; //Don't use a status move if partner wants to help - if (score < 0) - return 0; //essentially 'dont use this move' - return score; } -static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { s32 dmg; u8 result; - s16 score = originalScore; if (IsTargetingPartner(battlerAtk, battlerDef)) - return originalScore; // don't try to faint your ally ever + return score; // don't try to faint your ally ever if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power == 0) - return originalScore; // can't make anything faint with no power + return score; // can't make anything faint with no power if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) && gBattleMoves[move].effect != EFFECT_EXPLOSION) { @@ -4428,8 +4334,8 @@ static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore } else { - if (GetMovePowerResult(move) == MOVE_POWER_DISCOURAGED) - return (score - 1); + if (GetMoveDamageResult(move) == MOVE_POWER_DISCOURAGED) + score--; if (AI_GetMoveEffectiveness(move) == AI_EFFECTIVENESS_x4) { @@ -4442,7 +4348,7 @@ static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore //AI_TryToFaint_CheckIfDanger if (!IsBattlerFaster(AI_CHECK_FASTER) && CanTargetFaintAi(battlerDef, battlerAtk)) { // AI_TryToFaint_Danger - if (GetMovePowerResult(move) != MOVE_POWER_BEST) + if (GetMoveDamageResult(move) != MOVE_POWER_BEST) score--; else score++; @@ -4451,32 +4357,487 @@ static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore return score; } -static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_CheckPartner(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { - + //TODO + return score; } -static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +{ + bool32 targetSameSide = IsTargetingPartner(battlerAtk, battlerDef); + // attacker data + u16 atkAbility = AI_GetAbility(battlerAtk); + // target data + u16 defAbility = AI_GetAbility(battlerDef); + // attacker partner data + u8 battlerAtkPartner = BATTLE_PARTNER(battlerAtk); + u16 partnerMove = GetAllyChosenMove(); + // move data + u16 moveEffect = gBattleMoves[move].effect; + u8 effectiveness = AI_GetMoveEffectiveness(move); + u8 atkPriority = GetMovePriority(battlerAtk, move); + + // targeting partner, check benefits of doing that instead + if (IsValidDoubleBattle(battlerAtk) && targetSameSide) + return AI_CheckPartner(battlerAtk, battlerAtkPartner, move, score); + + // check move results + if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) + return 0; + + // if target goes first and can kill us, lets try to use a priority move to at least do something + if ((gBattleMons[battlerDef].status2 & (STATUS2_RECHARGE | STATUS2_BIDE)) + && CanTargetFaintAi(battlerAtk, battlerDef) + && IsBattlerFaster(AI_CHECK_SLOWER) + && atkPriority > 0) + score += 5; + + // if target is evasive and this move damages/always hits, use it + if (!IS_MOVE_STATUS(move) && gBattleMoves[move].accuracy == 0) + { + if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 10) + score++; + else if (gBattleMons[battlerAtk].statStages[STAT_ACC] <= 3) + score++; + else if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 7 && (Random() % 256) < 100) + score++; + else if (gBattleMons[battlerAtk].statStages[STAT_ACC] <= 4 && (Random() % 256 < 100)) + score++; + } + + // prefer good damaging moves + if (GetMoveDamageResult(move) == MOVE_POWER_BEST) + score += 2; + else if (GetMoveDamageResult(move) == MOVE_POWER_GOOD && (Random() % 256) < 100) + score++; + + // check status move preference + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_PREFER_STATUS_MOVES && IS_MOVE_STATUS(move)) + score++; + + // check high crit + if (TestMoveFlags(move, FLAG_HIGH_CRIT) && effectiveness >= AI_EFFECTIVENESS_x2) + score++; + + switch (moveEffect) + { + case EFFECT_HIT: + break; + case EFFECT_SLEEP: + case EFFECT_YAWN: + if (AI_CanPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + score++; + if ((HasMoveEffect(battlerAtk, EFFECT_DREAM_EATER) || HasMoveEffect(battlerAtk, EFFECT_NIGHTMARE)) && + !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) + score++; + break; + case EFFECT_DREAM_EATER: + if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) + break; + score++; // if target is asleep, dream eater is a pretty good move already + // fallthrough + case EFFECT_ABSORB: + if (ShouldRecover(battlerAtk, battlerDef, move, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex])) + score += 2; + break; + case EFFECT_EXPLOSION: + case EFFECT_MEMENTO: + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7) + { + if (GetHealthPercentage(battlerAtk) < 50 && (Random() % 2)) + score++; + } + break; + case EFFECT_MIRROR_MOVE: + if (gLastMoves[battlerDef] != MOVE_NONE) + return AI_CheckGoodMove(battlerAtk, battlerDef, gLastMoves[battlerDef], score); + break; + case EFFECT_ATTACK_UP: + case EFFECT_ATTACK_UP_2: + //AI_CV_AttackUp + break; + case EFFECT_DEFENSE_UP: + case EFFECT_DEFENSE_UP_2: + //AI_CV_DefenseUp + break; + case EFFECT_SPEED_UP: + case EFFECT_SPEED_UP_2: + //AI_CV_SpeedUp + break; + case EFFECT_SPECIAL_ATTACK_UP: + case EFFECT_SPECIAL_ATTACK_UP_2: + //AI_CV_SpAtkUp + break; + case EFFECT_SPECIAL_DEFENSE_UP: + case EFFECT_SPECIAL_DEFENSE_UP_2: + //AI_CV_SpDefUp + break; + case EFFECT_ACCURACY_UP: + case EFFECT_ACCURACY_UP_2: + //AI_CV_AccuracyUp + break; + case EFFECT_EVASION_UP: + case EFFECT_EVASION_UP_2: + //AI_CV_EvasionUp + break; + case EFFECT_ATTACK_DOWN: + case EFFECT_ATTACK_DOWN_2: + //AI_CV_AttackDown + break; + case EFFECT_DEFENSE_DOWN: + case EFFECT_DEFENSE_DOWN_2: + //AI_CV_DefenseDown + break; + case EFFECT_SPEED_DOWN: + case EFFECT_SPEED_DOWN_2: + //AI_CV_SpeedDown + break; + case EFFECT_SPECIAL_ATTACK_DOWN: + case EFFECT_SPECIAL_ATTACK_DOWN_2: + //AI_CV_SpAtkDown + break; + case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN_2: + //AI_CV_SpDefDown + break; + case EFFECT_ACCURACY_DOWN: + case EFFECT_ACCURACY_DOWN_2: + //AI_CV_AccuracyDown + break; + case EFFECT_EVASION_DOWN: + case EFFECT_EVASION_DOWN_2: + //AI_CV_EvasionDown + break; + case EFFECT_HAZE: + //AI_CV_Hazes + break; + case EFFECT_BIDE: + //AI_CV_Bide + break; + case EFFECT_ROAR: + //AI_CV_Roar + break; + case EFFECT_CONVERSION: + //AI_CV_Conversion + break; + case EFFECT_RESTORE_HP: + //AI_CV_Heal + break; + case EFFECT_SOFTBOILED: + //AI_CV_Heal + break; + case EFFECT_SWALLOW: + //AI_CV_Heal + break; + case EFFECT_ROOST: + //AI_CV_Heal + break; + case EFFECT_TOXIC: + //AI_CV_Toxic + break; + case EFFECT_LIGHT_SCREEN: + //AI_CV_LightScreen + break; + case EFFECT_REST: + //AI_CV_Rest + break; + case EFFECT_OHKO: + //AI_CV_OneHitKO + break; + case EFFECT_SUPER_FANG: + //AI_CV_SuperFang + break; + case EFFECT_TRAP: + //AI_CV_Trap + break; + case EFFECT_CONFUSE: + //AI_CV_Confuse + break; + case EFFECT_FOCUS_ENERGY: + //AI_CV_FocusEnergy + break; + case EFFECT_REFLECT: + //AI_CV_Reflect + break; + case EFFECT_AURORA_VEIL: + //AI_CV_AuroraVeil + break; + case EFFECT_POISON: + //AI_CV_Poison + break; + case EFFECT_TOXIC_THREAD: + //AI_CV_ToxicThread + break; + case EFFECT_PARALYZE: + //AI_CV_Paralyze + break; + case EFFECT_SWAGGER: + //AI_CV_Swagger + break; + case EFFECT_SPEED_DOWN_HIT: + //AI_CV_SpeedDownFromChance + break; + case EFFECT_TWO_TURNS_ATTACK: + //AI_CV_ChargeUpMove + break; + case EFFECT_VITAL_THROW: + //AI_CV_VitalThrow + break; + case EFFECT_SUBSTITUTE: + //AI_CV_Substitute + break; + case EFFECT_RECHARGE: + //AI_CV_Recharge + break; + case EFFECT_LEECH_SEED: + //AI_CV_LeechSeed + break; + case EFFECT_DISABLE: + //AI_CV_Disable + break; + case EFFECT_COUNTER: + //AI_CV_Counter + break; + case EFFECT_ENCORE: + //AI_CV_Encore + break; + case EFFECT_PAIN_SPLIT: + //AI_CV_PainSplit + break; + case EFFECT_LOCK_ON: + //AI_CV_LockOn + break; + case EFFECT_SLEEP_TALK: + //AI_CV_SleepTalk + break; + case EFFECT_SNORE: + //AI_CV_SleepTalk + break; + case EFFECT_DESTINY_BOND: + //AI_CV_DestinyBond + break; + case EFFECT_FLAIL: + //AI_CV_Flail + break; + case EFFECT_HEAL_BELL: + //AI_CV_HealBell + break; + case EFFECT_THIEF: + //AI_CV_Thief + break; + case EFFECT_MEAN_LOOK: + //AI_CV_Trap + break; + case EFFECT_MINIMIZE: + //AI_CV_EvasionUp + break; + case EFFECT_CURSE: + //AI_CV_Curse + break; + case EFFECT_PROTECT: + //AI_CV_Protect + break; + case EFFECT_FORESIGHT: + //AI_CV_Foresight + break; + case EFFECT_ENDURE: + //AI_CV_Endure + break; + case EFFECT_BATON_PASS: + //AI_CV_BatonPass + break; + case EFFECT_PURSUIT: + //AI_CV_Pursuit + break; + case EFFECT_MORNING_SUN: + //AI_CV_HealWeather + break; + case EFFECT_SYNTHESIS: + //AI_CV_HealWeather + break; + case EFFECT_MOONLIGHT: + //AI_CV_HealWeather + break; + case EFFECT_SHORE_UP: + //AI_CV_Heal + break; + case EFFECT_RAIN_DANCE: + //AI_CV_RainDance + break; + case EFFECT_SUNNY_DAY: + //AI_CV_SunnyDay + break; + case EFFECT_BELLY_DRUM: + //AI_CV_BellyDrum + break; + case EFFECT_PSYCH_UP: + //AI_CV_PsychUp + break; + case EFFECT_MIRROR_COAT: + //AI_CV_MirrorCoat + break; + case EFFECT_SKULL_BASH: + //AI_CV_ChargeUpMove + break; + case EFFECT_SOLARBEAM: + //AI_CV_ChargeUpMove + break; + break; + case EFFECT_GEOMANCY: + //AI_CV_Geomancy + break; + case EFFECT_SEMI_INVULNERABLE: + //AI_CV_SemiInvulnerable + break; + case EFFECT_FAKE_OUT: + //AI_CV_FakeOut + break; + case EFFECT_SPIT_UP: + //AI_CV_SpitUp + break; + case EFFECT_HAIL: + //AI_CV_Sandstorm + break; + case EFFECT_SANDSTORM: + //AI_CV_Sandstorm + break; + case EFFECT_FLATTER: + //AI_CV_Flatter + break; + case EFFECT_FACADE: + //AI_CV_Facade + break; + case EFFECT_FOCUS_PUNCH: + //AI_CV_FocusPunch + break; + case EFFECT_SMELLINGSALT: + //AI_CV_SmellingSalt + break; + case EFFECT_TRICK: + //AI_CV_Trick + break; + case EFFECT_ROLE_PLAY: + //AI_CV_ChangeSelfAbility + break; + case EFFECT_SUPERPOWER: + //AI_CV_Superpower + break; + case EFFECT_MAGIC_COAT: + //AI_CV_MagicCoat + break; + case EFFECT_RECYCLE: + //AI_CV_Recycle + break; + case EFFECT_REVENGE: + //AI_CV_Revenge + break; + case EFFECT_BRICK_BREAK: + //AI_CV_BrickBreak + break; + case EFFECT_KNOCK_OFF: + //AI_CV_KnockOff + break; + case EFFECT_ENDEAVOR: + //AI_CV_Endeavor + break; + case EFFECT_ERUPTION: + //AI_CV_Eruption + break; + case EFFECT_SKILL_SWAP: + //AI_CV_ChangeSelfAbility + break; + case EFFECT_IMPRISON: + //AI_CV_Imprison + break; + case EFFECT_REFRESH: + //AI_CV_Refresh + break; + case EFFECT_SNATCH: + //AI_CV_Snatch + break; + case EFFECT_MUD_SPORT: + //AI_CV_MudSport + break; + case EFFECT_OVERHEAT: + //AI_CV_Overheat + break; + case EFFECT_TICKLE: + //AI_CV_DefenseDown + break; + case EFFECT_COSMIC_POWER: + //AI_CV_SpDefUp + break; + case EFFECT_BULK_UP: + //AI_CV_DefenseUp + break; + case EFFECT_WATER_SPORT: + //AI_CV_WaterSport + break; + case EFFECT_CALM_MIND: + //AI_CV_SpDefUp + break; + case EFFECT_DRAGON_DANCE: + //AI_CV_DragonDance + break; + case EFFECT_POWDER: + //AI_CV_Powder + break; + case EFFECT_MISTY_TERRAIN: + //AI_CV_MistyTerrain + break; + case EFFECT_GRASSY_TERRAIN: + //AI_CV_GrassyTerrain + break; + case EFFECT_ELECTRIC_TERRAIN: + //AI_CV_ElectricTerrain + break; + case EFFECT_PSYCHIC_TERRAIN: + //AI_CV_PsychicTerrain + break; + case EFFECT_STEALTH_ROCK: + //AI_CV_Hazards + break; + case EFFECT_SPIKES: + //AI_CV_Hazards + break; + case EFFECT_STICKY_WEB: + //AI_CV_Hazards + break; + case EFFECT_TOXIC_SPIKES: + //AI_CV_Hazards + break; + case EFFECT_PERISH_SONG: + //AI_CV_PerishSong + break; + + + + + } // move effect switch +} + +static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } @@ -4490,16 +4851,16 @@ static void AI_Watch(void) AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); } -static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (IsBattlerTrapped(battlerAtk, FALSE)) - return originalScore; + return score; AI_Flee(); - return originalScore; + return score; } -static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { u8 safariFleeRate = gBattleStruct->safariEscapeFactor * 5; // Safari flee rate, from 0-20. @@ -4508,15 +4869,15 @@ static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) else AI_Watch(); - return originalScore; + return score; } -static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (GetHealthPercentage(battlerDef) <= 20) AI_Flee(); - return originalScore; + return score; } diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 3d3bdc4c01..34a42b6237 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -1,6 +1,7 @@ #include "global.h" #include "battle.h" #include "battle_ai_script_commands.h" +#include "battle_ai_util.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_setup.h" diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 0fa9509a1f..324a312378 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -266,6 +266,63 @@ bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch) return FALSE; } +// move checks +static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef) +{ + bool32 isCrit; + + switch (CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE)) + { + case -1: + case 0: + default: + isCrit = FALSE; + break; + case 1: + if (gBattleMoves[move].flags & FLAG_HIGH_CRIT && (Random() % 5 == 0)) + isCrit = TRUE; + else + isCrit = FALSE; + break; + case 2: + if (gBattleMoves[move].flags & FLAG_HIGH_CRIT && (Random() % 2 == 0)) + isCrit = TRUE; + else if (!(gBattleMoves[move].flags & FLAG_HIGH_CRIT) && (Random() % 4) == 0) + isCrit = TRUE; + else + isCrit = FALSE; + break; + case -2: + case 3: + case 4: + isCrit = TRUE; + break; + } + + return isCrit; +} + +s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) +{ + s32 dmg, moveType; + + SaveBattlerData(battlerAtk); + SaveBattlerData(battlerDef); + + SetBattlerData(battlerAtk); + SetBattlerData(battlerDef); + + gBattleStruct->dynamicMoveType = 0; + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + dmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, AI_GetIfCrit(move, battlerAtk, battlerDef), FALSE, FALSE); + + RestoreBattlerData(battlerAtk); + RestoreBattlerData(battlerDef); + + return dmg; +} + // Checks if one of the moves has side effects or perks static u32 WhichMoveBetter(u32 move1, u32 move2) { @@ -324,7 +381,7 @@ static u32 WhichMoveBetter(u32 move1, u32 move2) return 2; } -u8 GetMovePowerResult(u16 move) +u8 GetMoveDamageResult(u16 move) { s32 i, checkedMove, bestId, currId, hp; s32 moveDmgs[MAX_MON_MOVES]; @@ -458,8 +515,8 @@ u8 AI_GetMoveEffectiveness(u16 move) return damageVar; } -// 0: is user(ai) faster -// 1: is target faster +// AI_CHECK_FASTER: is user(ai) faster +// AI_CHECK_SLOWER: is target faster bool32 IsBattlerFaster(u8 battler) { u32 fasterAI = 0, fasterPlayer = 0, i; @@ -525,6 +582,26 @@ bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk) return FALSE; } +// Check if target has means to faint ai mon after modding hp/dmg +bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod) +{ + u32 i; + u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP); + u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + u32 dmg = AI_CalcDamage(moves[i], battlerDef, battlerAtk) + dmgMod; + u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod; + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i]) && dmg >= hpCheck) + { + return TRUE; + } + } + + return FALSE; +} + // does NOT include ability suppression checks s32 AI_GetAbility(u32 battlerId) { @@ -954,42 +1031,6 @@ bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index) return FALSE; } -s32 CountUsablePartyMons(u8 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(GetBattlerPosition(battlerId) ^ BIT_FLANK)]; - } - 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_SPECIES2) != SPECIES_NONE - && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG) - { - ret++; - } - } - - return ret; -} - u16 *GetMovesArray(u32 battler) { if (IsBattlerAIControlled(battler) || IsBattlerAIControlled(BATTLE_PARTNER(battler))) @@ -1026,6 +1067,20 @@ bool32 HasMoveWithType(u32 battler, u8 type) return FALSE; } +bool32 HasMoveEffect(u32 battlerId, u16 moveEffect) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && gBattleMoves[moves[i]].effect == moveEffect) + return TRUE; + } + + return FALSE; +} + bool32 IsInstructBannedMove(u16 move) { u32 i; @@ -1251,7 +1306,7 @@ bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability) } // status checks -bool32 AI_ShouldPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { if (defAbility == ABILITY_INSOMNIA || defAbility == ABILITY_VITAL_SPIRIT @@ -1264,7 +1319,7 @@ bool32 AI_ShouldPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 mov return TRUE; } -bool32 AI_ShouldPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { if (defAbility == ABILITY_IMMUNITY || defAbility == ABILITY_PASTEL_VEIL @@ -1358,28 +1413,6 @@ bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof) return FALSE; } -bool32 IsPartyFullyHealedExceptBattler(u8 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_SPECIES2) != SPECIES_NONE - && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG - && GetMonData(&party[i], MON_DATA_HP) < GetMonData(&party[i], MON_DATA_MAX_HP)) - return FALSE; - } - return TRUE; -} - u16 GetBattlerSideSpeedAverage(u8 battler) { u16 speed1 = 0; @@ -1415,6 +1448,30 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI return TRUE; } +bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) +{ + if (move == 0xFFFF || GetWhoStrikesFirst(sBattler_AI, gBattlerTarget, TRUE) == 0) + { + // using item or user goes first + u8 healPercent = (gBattleMoves[move].argument == 0) ? 50 : gBattleMoves[move].argument; + s32 healDmg = (healPercent * damage) / 100; + + if (CanTargetFaintAi(battlerDef, battlerAtk) + && !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healDmg, 0)) + return TRUE; // target can faint attacker unless they heal + else if (!CanTargetFaintAi(battlerDef, battlerAtk) && GetHealthPercentage(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; +} + // Partner Logic bool32 IsValidDoubleBattle(u8 battlerAtk) { @@ -1556,3 +1613,82 @@ bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove return FALSE; } +// party logic +s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon) +{ + s32 dmg; + u32 i; + struct BattlePokemon *battleMons = Alloc(sizeof(struct BattlePokemon) * MAX_BATTLERS_COUNT); + + for (i = 0; i < MAX_BATTLERS_COUNT; i++) + battleMons[i] = gBattleMons[i]; + + PokemonToBattleMon(mon, &gBattleMons[battlerAtk]); + dmg = AI_CalcDamage(move, battlerAtk, battlerDef); + + for (i = 0; i < MAX_BATTLERS_COUNT; i++) + gBattleMons[i] = battleMons[i]; + + Free(battleMons); + + return dmg; +} + +s32 CountUsablePartyMons(u8 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(GetBattlerPosition(battlerId) ^ BIT_FLANK)]; + } + 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_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG) + { + ret++; + } + } + + return ret; +} + +bool32 IsPartyFullyHealedExceptBattler(u8 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_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG + && GetMonData(&party[i], MON_DATA_HP) < GetMonData(&party[i], MON_DATA_MAX_HP)) + return FALSE; + } + return TRUE; +} + diff --git a/src/battle_factory.c b/src/battle_factory.c index 98af96664c..e54796196b 100644 --- a/src/battle_factory.c +++ b/src/battle_factory.c @@ -850,13 +850,13 @@ u32 GetAiScriptsInBattleFactory(void) int challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7; if (gTrainerBattleOpponent_A == TRAINER_FRONTIER_BRAIN) - return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY; + return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE; else if (challengeNum < 2) return 0; else if (challengeNum < 4) return AI_FLAG_CHECK_BAD_MOVE; else - return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY; + return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE; } } diff --git a/src/battle_main.c b/src/battle_main.c index 48129c5230..b46527b80c 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -2,6 +2,7 @@ #include "battle.h" #include "battle_anim.h" #include "battle_ai_script_commands.h" +#include "battle_ai_util.h" #include "battle_arena.h" #include "battle_controllers.h" #include "battle_interface.h" diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9872d04fe9..a72feb87c5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -5,6 +5,7 @@ #include "battle_message.h" #include "battle_anim.h" #include "battle_ai_script_commands.h" +#include "battle_ai_util.h" #include "battle_scripts.h" #include "constants/moves.h" #include "constants/abilities.h" diff --git a/src/battle_util.c b/src/battle_util.c index 846e269b13..40260bbe15 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -24,6 +24,7 @@ #include "window.h" #include "battle_message.h" #include "battle_ai_script_commands.h" +#include "battle_ai_util.h" #include "event_data.h" #include "link.h" #include "malloc.h" diff --git a/src/data/trainers.h b/src/data/trainers.h index 619763ea11..5712fc1442 100644 --- a/src/data/trainers.h +++ b/src/data/trainers.h @@ -22,7 +22,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Sawyer1), .party = {.NoItemDefaultMoves = sParty_Sawyer1}, }, @@ -162,7 +162,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARCEL"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Marcel), .party = {.NoItemDefaultMoves = sParty_Marcel}, }, @@ -414,7 +414,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FREDRICK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Fredrick), .party = {.NoItemDefaultMoves = sParty_Fredrick}, }, @@ -428,7 +428,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MATT"), .items = {ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Matt), .party = {.NoItemDefaultMoves = sParty_Matt}, }, @@ -456,7 +456,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_ShellyWeatherInstitute), .party = {.NoItemDefaultMoves = sParty_ShellyWeatherInstitute}, }, @@ -470,7 +470,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_ShellySeafloorCavern), .party = {.NoItemDefaultMoves = sParty_ShellySeafloorCavern}, }, @@ -484,7 +484,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ARCHIE"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Archie), .party = {.NoItemDefaultMoves = sParty_Archie}, }, @@ -540,7 +540,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FELIX"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Felix), .party = {.NoItemCustomMoves = sParty_Felix}, }, @@ -1002,7 +1002,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RANDALL"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Randall), .party = {.ItemCustomMoves = sParty_Randall}, }, @@ -1016,7 +1016,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PARKER"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Parker), .party = {.ItemCustomMoves = sParty_Parker}, }, @@ -1030,7 +1030,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GEORGE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_George), .party = {.ItemCustomMoves = sParty_George}, }, @@ -1044,7 +1044,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERKE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Berke), .party = {.ItemCustomMoves = sParty_Berke}, }, @@ -1058,7 +1058,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAXTON"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Braxton), .party = {.NoItemCustomMoves = sParty_Braxton}, }, @@ -1072,7 +1072,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VINCENT"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Vincent), .party = {.NoItemDefaultMoves = sParty_Vincent}, }, @@ -1086,7 +1086,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEROY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Leroy), .party = {.NoItemDefaultMoves = sParty_Leroy}, }, @@ -1100,7 +1100,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wilton1), .party = {.NoItemDefaultMoves = sParty_Wilton1}, }, @@ -1114,7 +1114,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDGAR"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Edgar), .party = {.NoItemDefaultMoves = sParty_Edgar}, }, @@ -1128,7 +1128,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALBERT"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Albert), .party = {.NoItemDefaultMoves = sParty_Albert}, }, @@ -1142,7 +1142,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAMUEL"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Samuel), .party = {.NoItemDefaultMoves = sParty_Samuel}, }, @@ -1156,7 +1156,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VITO"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Vito), .party = {.NoItemDefaultMoves = sParty_Vito}, }, @@ -1170,7 +1170,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("OWEN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Owen), .party = {.NoItemDefaultMoves = sParty_Owen}, }, @@ -1184,7 +1184,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wilton2), .party = {.NoItemDefaultMoves = sParty_Wilton2}, }, @@ -1198,7 +1198,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wilton3), .party = {.NoItemDefaultMoves = sParty_Wilton3}, }, @@ -1212,7 +1212,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wilton4), .party = {.NoItemDefaultMoves = sParty_Wilton4}, }, @@ -1226,7 +1226,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wilton5), .party = {.NoItemDefaultMoves = sParty_Wilton5}, }, @@ -1240,7 +1240,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WARREN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Warren), .party = {.NoItemDefaultMoves = sParty_Warren}, }, @@ -1254,7 +1254,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Mary), .party = {.ItemCustomMoves = sParty_Mary}, }, @@ -1268,7 +1268,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEXIA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Alexia), .party = {.ItemCustomMoves = sParty_Alexia}, }, @@ -1324,7 +1324,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brooke1), .party = {.NoItemDefaultMoves = sParty_Brooke1}, }, @@ -1338,7 +1338,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNIFER"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Jennifer), .party = {.NoItemDefaultMoves = sParty_Jennifer}, }, @@ -1352,7 +1352,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HOPE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Hope), .party = {.NoItemDefaultMoves = sParty_Hope}, }, @@ -1366,7 +1366,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHANNON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Shannon), .party = {.NoItemDefaultMoves = sParty_Shannon}, }, @@ -1380,7 +1380,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MICHELLE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Michelle), .party = {.NoItemDefaultMoves = sParty_Michelle}, }, @@ -1394,7 +1394,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAROLINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Caroline), .party = {.NoItemDefaultMoves = sParty_Caroline}, }, @@ -1408,7 +1408,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JULIE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Julie), .party = {.NoItemDefaultMoves = sParty_Julie}, }, @@ -1422,7 +1422,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brooke2), .party = {.NoItemDefaultMoves = sParty_Brooke2}, }, @@ -1436,7 +1436,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brooke3), .party = {.NoItemDefaultMoves = sParty_Brooke3}, }, @@ -1450,7 +1450,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brooke4), .party = {.NoItemDefaultMoves = sParty_Brooke4}, }, @@ -1464,7 +1464,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brooke5), .party = {.NoItemDefaultMoves = sParty_Brooke5}, }, @@ -3662,7 +3662,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SIDNEY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Sidney), .party = {.ItemCustomMoves = sParty_Sidney}, }, @@ -3676,7 +3676,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PHOEBE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Phoebe), .party = {.ItemCustomMoves = sParty_Phoebe}, }, @@ -3690,7 +3690,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GLACIA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Glacia), .party = {.ItemCustomMoves = sParty_Glacia}, }, @@ -3704,7 +3704,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DRAKE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Drake), .party = {.ItemCustomMoves = sParty_Drake}, }, @@ -3718,7 +3718,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_POTION, ITEM_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Roxanne1), .party = {.ItemCustomMoves = sParty_Roxanne1}, }, @@ -3732,7 +3732,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brawly1), .party = {.ItemCustomMoves = sParty_Brawly1}, }, @@ -3746,7 +3746,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wattson1), .party = {.ItemCustomMoves = sParty_Wattson1}, }, @@ -3760,7 +3760,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Flannery1), .party = {.ItemCustomMoves = sParty_Flannery1}, }, @@ -3774,7 +3774,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Norman1), .party = {.ItemCustomMoves = sParty_Norman1}, }, @@ -3788,7 +3788,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona1), .party = {.ItemCustomMoves = sParty_Winona1}, }, @@ -3802,7 +3802,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_HYPER_POTION}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_TateAndLiza1), .party = {.ItemCustomMoves = sParty_TateAndLiza1}, }, @@ -3816,7 +3816,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Juan1), .party = {.ItemCustomMoves = sParty_Juan1}, }, @@ -4306,7 +4306,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Timothy1), .party = {.NoItemDefaultMoves = sParty_Timothy1}, }, @@ -4320,7 +4320,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Timothy2), .party = {.NoItemCustomMoves = sParty_Timothy2}, }, @@ -4334,7 +4334,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Timothy3), .party = {.NoItemCustomMoves = sParty_Timothy3}, }, @@ -4348,7 +4348,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Timothy4), .party = {.NoItemCustomMoves = sParty_Timothy4}, }, @@ -4362,7 +4362,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Timothy5), .party = {.NoItemCustomMoves = sParty_Timothy5}, }, @@ -4376,7 +4376,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Vicky), .party = {.NoItemCustomMoves = sParty_Vicky}, }, @@ -4390,7 +4390,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Shelby1), .party = {.NoItemDefaultMoves = sParty_Shelby1}, }, @@ -4404,7 +4404,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Shelby2), .party = {.NoItemDefaultMoves = sParty_Shelby2}, }, @@ -4418,7 +4418,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Shelby3), .party = {.NoItemDefaultMoves = sParty_Shelby3}, }, @@ -4432,7 +4432,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Shelby4), .party = {.NoItemDefaultMoves = sParty_Shelby4}, }, @@ -4446,7 +4446,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Shelby5), .party = {.NoItemDefaultMoves = sParty_Shelby5}, }, @@ -4544,7 +4544,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("QUINCY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Quincy), .party = {.NoItemCustomMoves = sParty_Quincy}, }, @@ -4558,7 +4558,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYNN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Katelynn), .party = {.NoItemCustomMoves = sParty_Katelynn}, }, @@ -4698,7 +4698,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLACE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wallace), .party = {.ItemCustomMoves = sParty_Wallace}, }, @@ -7050,7 +7050,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAZMYN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Jazmyn), .party = {.NoItemDefaultMoves = sParty_Jazmyn}, }, @@ -7064,7 +7064,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JONAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Jonas), .party = {.NoItemCustomMoves = sParty_Jonas}, }, @@ -7120,7 +7120,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARLEY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Marley), .party = {.ItemCustomMoves = sParty_Marley}, }, @@ -7274,7 +7274,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_WallyVR1), .party = {.NoItemCustomMoves = sParty_WallyVR1}, }, @@ -7288,7 +7288,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRoute103Mudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRoute103Mudkip}, }, @@ -7302,7 +7302,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRoute110Mudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRoute110Mudkip}, }, @@ -7316,7 +7316,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRoute119Mudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRoute119Mudkip}, }, @@ -7344,7 +7344,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRoute110Treecko), .party = {.NoItemDefaultMoves = sParty_BrendanRoute110Treecko}, }, @@ -7358,7 +7358,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRoute119Treecko), .party = {.NoItemDefaultMoves = sParty_BrendanRoute119Treecko}, }, @@ -7372,7 +7372,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRoute103Torchic), .party = {.NoItemDefaultMoves = sParty_BrendanRoute103Torchic}, }, @@ -7386,7 +7386,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRoute110Torchic), .party = {.NoItemDefaultMoves = sParty_BrendanRoute110Torchic}, }, @@ -7400,7 +7400,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRoute119Torchic), .party = {.NoItemDefaultMoves = sParty_BrendanRoute119Torchic}, }, @@ -7414,7 +7414,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRoute103Mudkip), .party = {.NoItemDefaultMoves = sParty_MayRoute103Mudkip}, }, @@ -7428,7 +7428,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRoute110Mudkip), .party = {.NoItemDefaultMoves = sParty_MayRoute110Mudkip}, }, @@ -7442,7 +7442,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRoute119Mudkip), .party = {.NoItemDefaultMoves = sParty_MayRoute119Mudkip}, }, @@ -7456,7 +7456,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRoute103Treecko), .party = {.NoItemDefaultMoves = sParty_MayRoute103Treecko}, }, @@ -7470,7 +7470,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRoute110Treecko), .party = {.NoItemDefaultMoves = sParty_MayRoute110Treecko}, }, @@ -7484,7 +7484,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRoute119Treecko), .party = {.NoItemDefaultMoves = sParty_MayRoute119Treecko}, }, @@ -7498,7 +7498,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRoute103Torchic), .party = {.NoItemDefaultMoves = sParty_MayRoute103Torchic}, }, @@ -7512,7 +7512,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRoute110Torchic), .party = {.NoItemDefaultMoves = sParty_MayRoute110Torchic}, }, @@ -7526,7 +7526,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRoute119Torchic), .party = {.NoItemDefaultMoves = sParty_MayRoute119Torchic}, }, @@ -7568,7 +7568,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MITCHELL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Mitchell), .party = {.NoItemCustomMoves = sParty_Mitchell}, }, @@ -7652,7 +7652,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HALLE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Halle), .party = {.NoItemDefaultMoves = sParty_Halle}, }, @@ -7736,7 +7736,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Jackson1), .party = {.NoItemDefaultMoves = sParty_Jackson1}, }, @@ -7750,7 +7750,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LORENZO"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Lorenzo), .party = {.NoItemDefaultMoves = sParty_Lorenzo}, }, @@ -7764,7 +7764,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SEBASTIAN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Sebastian), .party = {.NoItemDefaultMoves = sParty_Sebastian}, }, @@ -7792,7 +7792,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Jackson3), .party = {.NoItemDefaultMoves = sParty_Jackson3}, }, @@ -7820,7 +7820,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Jackson5), .party = {.NoItemDefaultMoves = sParty_Jackson5}, }, @@ -7862,7 +7862,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SOPHIA"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Sophia), .party = {.NoItemDefaultMoves = sParty_Sophia}, }, @@ -7890,7 +7890,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CATHERINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Catherine3), .party = {.NoItemDefaultMoves = sParty_Catherine3}, }, @@ -7918,7 +7918,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CATHERINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Catherine5), .party = {.NoItemDefaultMoves = sParty_Catherine5}, }, @@ -8086,7 +8086,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ATHENA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Athena), .party = {.ItemCustomMoves = sParty_Athena}, }, @@ -8324,7 +8324,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAXTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Paxton), .party = {.NoItemDefaultMoves = sParty_Paxton}, }, @@ -8366,7 +8366,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TABITHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_TabithaMtChimney), .party = {.NoItemDefaultMoves = sParty_TabithaMtChimney}, }, @@ -8394,7 +8394,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanRustboroTorchic), .party = {.NoItemDefaultMoves = sParty_BrendanRustboroTorchic}, }, @@ -8422,7 +8422,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAXIE"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MaxieMagmaHideout), .party = {.NoItemDefaultMoves = sParty_MaxieMagmaHideout}, }, @@ -8436,7 +8436,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAXIE"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MaxieMtChimney), .party = {.NoItemDefaultMoves = sParty_MaxieMtChimney}, }, @@ -8492,7 +8492,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VIVI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Vivi), .party = {.NoItemDefaultMoves = sParty_Vivi}, }, @@ -9080,7 +9080,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GERALD"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Gerald), .party = {.NoItemCustomMoves = sParty_Gerald}, }, @@ -9192,7 +9192,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_WallyMauville), .party = {.NoItemDefaultMoves = sParty_WallyMauville}, }, @@ -9206,7 +9206,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_WallyVR2), .party = {.NoItemCustomMoves = sParty_WallyVR2}, }, @@ -9220,7 +9220,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_WallyVR3), .party = {.NoItemCustomMoves = sParty_WallyVR3}, }, @@ -9234,7 +9234,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_WallyVR4), .party = {.NoItemCustomMoves = sParty_WallyVR4}, }, @@ -9248,7 +9248,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_WallyVR5), .party = {.NoItemCustomMoves = sParty_WallyVR5}, }, @@ -9262,7 +9262,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanLilycoveMudkip), .party = {.NoItemDefaultMoves = sParty_BrendanLilycoveMudkip}, }, @@ -9276,7 +9276,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanLilycoveTreecko), .party = {.NoItemDefaultMoves = sParty_BrendanLilycoveTreecko}, }, @@ -9290,7 +9290,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_BrendanLilycoveTorchic), .party = {.NoItemDefaultMoves = sParty_BrendanLilycoveTorchic}, }, @@ -9304,7 +9304,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayLilycoveMudkip), .party = {.NoItemDefaultMoves = sParty_MayLilycoveMudkip}, }, @@ -9318,7 +9318,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayLilycoveTreecko), .party = {.NoItemDefaultMoves = sParty_MayLilycoveTreecko}, }, @@ -9332,7 +9332,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayLilycoveTorchic), .party = {.NoItemDefaultMoves = sParty_MayLilycoveTorchic}, }, @@ -9388,7 +9388,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEXA"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Alexa), .party = {.NoItemDefaultMoves = sParty_Alexa}, }, @@ -9402,7 +9402,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RUBEN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Ruben), .party = {.NoItemDefaultMoves = sParty_Ruben}, }, @@ -9542,7 +9542,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_JohnAndJay1), .party = {.NoItemCustomMoves = sParty_JohnAndJay1}, }, @@ -9556,7 +9556,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_JohnAndJay2), .party = {.NoItemCustomMoves = sParty_JohnAndJay2}, }, @@ -9570,7 +9570,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_JohnAndJay3), .party = {.NoItemCustomMoves = sParty_JohnAndJay3}, }, @@ -9598,7 +9598,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_JohnAndJay5), .party = {.NoItemCustomMoves = sParty_JohnAndJay5}, }, @@ -10270,7 +10270,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARCY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Darcy), .party = {.NoItemDefaultMoves = sParty_Darcy}, }, @@ -10284,7 +10284,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAXIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MaxieMossdeep), .party = {.NoItemDefaultMoves = sParty_MaxieMossdeep}, }, @@ -10382,7 +10382,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAROLINA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Carolina), .party = {.NoItemDefaultMoves = sParty_Carolina}, }, @@ -10620,7 +10620,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAKAYLA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Makayla), .party = {.NoItemDefaultMoves = sParty_Makayla}, }, @@ -10676,7 +10676,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEONEL"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Leonel), .party = {.NoItemCustomMoves = sParty_Leonel}, }, @@ -10746,7 +10746,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Cristin1), .party = {.NoItemDefaultMoves = sParty_Cristin1}, }, @@ -10760,7 +10760,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRustboroTreecko), .party = {.NoItemDefaultMoves = sParty_MayRustboroTreecko}, }, @@ -10774,7 +10774,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_MayRustboroTorchic), .party = {.NoItemDefaultMoves = sParty_MayRustboroTorchic}, }, @@ -10788,7 +10788,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Roxanne2), .party = {.ItemCustomMoves = sParty_Roxanne2}, }, @@ -10802,7 +10802,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Roxanne3), .party = {.ItemCustomMoves = sParty_Roxanne3}, }, @@ -10816,7 +10816,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Roxanne4), .party = {.ItemCustomMoves = sParty_Roxanne4}, }, @@ -10830,7 +10830,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Roxanne5), .party = {.ItemCustomMoves = sParty_Roxanne5}, }, @@ -10844,7 +10844,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brawly2), .party = {.ItemCustomMoves = sParty_Brawly2}, }, @@ -10858,7 +10858,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brawly3), .party = {.ItemCustomMoves = sParty_Brawly3}, }, @@ -10872,7 +10872,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brawly4), .party = {.ItemCustomMoves = sParty_Brawly4}, }, @@ -10886,7 +10886,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brawly5), .party = {.ItemCustomMoves = sParty_Brawly5}, }, @@ -10900,7 +10900,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wattson2), .party = {.ItemCustomMoves = sParty_Wattson2}, }, @@ -10914,7 +10914,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wattson3), .party = {.ItemCustomMoves = sParty_Wattson3}, }, @@ -10928,7 +10928,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wattson4), .party = {.ItemCustomMoves = sParty_Wattson4}, }, @@ -10942,7 +10942,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Wattson5), .party = {.ItemCustomMoves = sParty_Wattson5}, }, @@ -10956,7 +10956,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Flannery2), .party = {.ItemCustomMoves = sParty_Flannery2}, }, @@ -10970,7 +10970,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Flannery3), .party = {.ItemCustomMoves = sParty_Flannery3}, }, @@ -10984,7 +10984,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Flannery4), .party = {.ItemCustomMoves = sParty_Flannery4}, }, @@ -10998,7 +10998,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Flannery5), .party = {.ItemCustomMoves = sParty_Flannery5}, }, @@ -11012,7 +11012,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Norman2), .party = {.ItemCustomMoves = sParty_Norman2}, }, @@ -11026,7 +11026,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Norman3), .party = {.ItemCustomMoves = sParty_Norman3}, }, @@ -11040,7 +11040,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Norman4), .party = {.ItemCustomMoves = sParty_Norman4}, }, @@ -11054,7 +11054,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Norman5), .party = {.ItemCustomMoves = sParty_Norman5}, }, @@ -11068,7 +11068,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona2), .party = {.ItemCustomMoves = sParty_Winona2}, }, @@ -11082,7 +11082,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona3), .party = {.ItemCustomMoves = sParty_Winona3}, }, @@ -11096,7 +11096,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona4), .party = {.ItemCustomMoves = sParty_Winona4}, }, @@ -11110,7 +11110,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona5), .party = {.ItemCustomMoves = sParty_Winona5}, }, @@ -11124,7 +11124,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_TateAndLiza2), .party = {.ItemCustomMoves = sParty_TateAndLiza2}, }, @@ -11138,7 +11138,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_TateAndLiza3), .party = {.ItemCustomMoves = sParty_TateAndLiza3}, }, @@ -11152,7 +11152,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_TateAndLiza4), .party = {.ItemCustomMoves = sParty_TateAndLiza4}, }, @@ -11166,7 +11166,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_TateAndLiza5), .party = {.ItemCustomMoves = sParty_TateAndLiza5}, }, @@ -11180,7 +11180,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Juan2), .party = {.ItemCustomMoves = sParty_Juan2}, }, @@ -11194,7 +11194,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Juan3), .party = {.ItemCustomMoves = sParty_Juan3}, }, @@ -11208,7 +11208,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Juan4), .party = {.ItemCustomMoves = sParty_Juan4}, }, @@ -11222,7 +11222,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Juan5), .party = {.ItemCustomMoves = sParty_Juan5}, }, @@ -11236,7 +11236,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANGELO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Angelo), .party = {.ItemCustomMoves = sParty_Angelo}, }, @@ -11250,7 +11250,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARIUS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Darius), .party = {.NoItemDefaultMoves = sParty_Darius}, }, @@ -11264,7 +11264,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("STEVEN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Steven), .party = {.ItemCustomMoves = sParty_Steven}, }, @@ -11278,7 +11278,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANABEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Anabel), .party = {.NoItemDefaultMoves = sParty_Anabel}, }, @@ -11292,7 +11292,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TUCKER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Tucker), .party = {.NoItemDefaultMoves = sParty_Tucker}, }, @@ -11306,7 +11306,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SPENSER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Spenser), .party = {.NoItemDefaultMoves = sParty_Spenser}, }, @@ -11320,7 +11320,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRETA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Greta), .party = {.NoItemDefaultMoves = sParty_Greta}, }, @@ -11334,7 +11334,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOLAND"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Noland), .party = {.NoItemDefaultMoves = sParty_Noland}, }, @@ -11348,7 +11348,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUCY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Lucy), .party = {.NoItemDefaultMoves = sParty_Lucy}, }, @@ -11362,7 +11362,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRANDON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Brandon), .party = {.NoItemDefaultMoves = sParty_Brandon}, }, @@ -11600,7 +11600,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Cristin2), .party = {.NoItemDefaultMoves = sParty_Cristin2}, }, @@ -11614,7 +11614,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Cristin3), .party = {.NoItemDefaultMoves = sParty_Cristin3}, }, @@ -11628,7 +11628,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Cristin4), .party = {.NoItemDefaultMoves = sParty_Cristin4}, }, @@ -11642,7 +11642,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Cristin5), .party = {.NoItemDefaultMoves = sParty_Cristin5}, }, @@ -11712,7 +11712,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Sawyer2), .party = {.NoItemDefaultMoves = sParty_Sawyer2}, }, @@ -11726,7 +11726,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Sawyer3), .party = {.NoItemDefaultMoves = sParty_Sawyer3}, }, @@ -11740,7 +11740,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Sawyer4), .party = {.NoItemDefaultMoves = sParty_Sawyer4}, }, @@ -11754,7 +11754,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, .partySize = ARRAY_COUNT(sParty_Sawyer5), .party = {.NoItemDefaultMoves = sParty_Sawyer5}, }, diff --git a/src/trainer_hill.c b/src/trainer_hill.c index 043522aee1..d7b4ee37ac 100644 --- a/src/trainer_hill.c +++ b/src/trainer_hill.c @@ -897,7 +897,7 @@ void FillHillTrainersParties(void) // hill trainers. u32 GetTrainerHillAIFlags(void) { - return (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); + return (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE); } u8 GetTrainerEncounterMusicIdInTrainerHill(u16 trainerId) From 8a544665e4203aa879c4e604c7bf047ee5056b5b Mon Sep 17 00:00:00 2001 From: Evan Date: Wed, 16 Dec 2020 22:56:10 -0700 Subject: [PATCH 06/36] move common ai params to preloaded struct --- include/battle.h | 22 ++ include/battle_ai_util.h | 3 + src/battle_ai_script_commands.c | 644 ++++++++++++++++---------------- src/battle_ai_util.c | 68 ++++ 4 files changed, 423 insertions(+), 314 deletions(-) diff --git a/include/battle.h b/include/battle.h index 17fd49e7ea..07b8289725 100644 --- a/include/battle.h +++ b/include/battle.h @@ -235,8 +235,29 @@ struct AI_SavedBattleMon u16 species; }; +struct AiLogicData +{ + //attacker data + u16 atkAbility; + u16 atkHoldEffect; + u8 atkParam; + // target data + u16 defAbility; + u16 defHoldEffect; + u8 defParam; + // attacker partner data + u8 battlerAtkPartner; + u16 partnerMove; + u16 atkPartnerAbility; + bool32 targetSameSide; + // target partner data + u8 battlerDefPartner; + u16 defPartnerAbility; +}; + struct AI_ThinkingStruct { + struct AiLogicData *data; u8 aiState; u8 movesetIndex; u16 moveConsidered; @@ -295,6 +316,7 @@ struct BattleResources }; #define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) +#define AI_DATA ((struct AiLogicData *)(gBattleResources->ai->data)) #define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) struct BattleResults diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 134fefc706..043235fa80 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -49,8 +49,10 @@ bool32 BattlerHasAnyStatRaised(u8 battlerId); u32 CountPositiveStatStages(u8 battlerId); u32 CountNegativeStatStages(u8 battlerId); bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability); +bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); // move checks +bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split); s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef); u8 GetMoveDamageResult(u16 move); u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); @@ -60,6 +62,7 @@ bool32 IsConfusionMoveEffect(u16 moveEffect); bool32 HasMoveWithSplit(u32 battler, u32 split); bool32 HasMoveWithType(u32 battler, u8 type); bool32 HasMoveEffect(u32 battlerId, u16 moveEffect); +bool32 HasMoveWithLowAccuracy(u8, u8, u8, bool32, u16, u16, u16, u16, u16); bool32 TestMoveFlagsInMoveset(u8 battler, u32 flags); bool32 IsAromaVeilProtectedMove(u16 move); bool32 IsNonVolatileStatusMoveEffect(u16 moveEffect); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 033db8e79d..2b666a16b9 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -503,6 +503,26 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) return FALSE; } +static void GetAiLogicData(u8 battlerAtk, u8 battlerDef) +{ + // attacker data + AI_DATA->atkAbility = AI_GetAbility(battlerAtk); + AI_DATA->atkHoldEffect = AI_GetHoldEffect(battlerAtk); + AI_DATA->atkParam = GetBattlerHoldEffectParam(battlerAtk); + // target data + AI_DATA->defAbility = AI_GetAbility(battlerDef); + AI_DATA->defHoldEffect = AI_GetHoldEffect(battlerDef); + AI_DATA->defParam = GetBattlerHoldEffectParam(battlerDef); + // attacker partner data + AI_DATA->battlerAtkPartner = BATTLE_PARTNER(battlerAtk); + AI_DATA->partnerMove = GetAllyChosenMove(); + AI_DATA->atkPartnerAbility = AI_GetAbility(AI_DATA->battlerAtkPartner); + AI_DATA->targetSameSide = IsTargetingPartner(battlerAtk, battlerDef); + // target partner data + AI_DATA->battlerDefPartner = BATTLE_PARTNER(battlerDef); + AI_DATA->defPartnerAbility = AI_GetAbility(AI_DATA->battlerDefPartner); +} + static u8 ChooseMoveOrAction_Singles(void) { u8 currentMoveArray[MAX_MON_MOVES]; @@ -512,7 +532,8 @@ static u8 ChooseMoveOrAction_Singles(void) u32 flags = AI_THINKING_STRUCT->aiFlags; RecordLastUsedMoveByTarget(); - + GetAiLogicData(sBattler_AI, gBattlerTarget); + while (flags != 0) { if (flags & 1) @@ -2116,32 +2137,6 @@ static void Cmd_if_has_no_move_with_split(void) gAIScriptPtr += 7; } -// 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. -static bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split) -{ - s32 i, moveType; - u32 usable = 0; - u32 unusable = CheckMoveLimitations(attacker, 0, 0xFF); - u16 *moves = GetMovesArray(attacker); - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (moves[i] != MOVE_NONE - && moves[i] != 0xFFFF - && GetBattleMoveSplit(moves[i]) == split - && !(unusable & gBitTable[i])) - { - SetTypeBeforeUsingMove(moves[i], attacker); - GET_MOVE_TYPE(moves[i], moveType); - if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, FALSE) != 0) - usable |= gBitTable[i]; - } - } - - return (usable == 0); -} - static void Cmd_if_physical_moves_unusable(void) { if (MovesWithSplitUnusable(BattleAI_GetWantedBattler(gAIScriptPtr[1]), BattleAI_GetWantedBattler(gAIScriptPtr[2]), SPLIT_PHYSICAL)) @@ -2348,31 +2343,15 @@ static void Cmd_if_has_move_with_accuracy_lt(void) // AI Functions static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { - // attacker data - u16 atkAbility = AI_GetAbility(battlerAtk); - u8 atkHoldEffect = AI_GetHoldEffect(battlerAtk); - u8 atkParam = GetBattlerHoldEffectParam(battlerAtk); - u8 atkPriority = GetMovePriority(battlerAtk, move); - // target data - u16 defAbility = AI_GetAbility(battlerDef); - u8 defHoldEffect = AI_GetHoldEffect(battlerDef); - u8 defParam = GetBattlerHoldEffectParam(battlerDef); - // attacker partner data - u8 battlerAtkPartner = BATTLE_PARTNER(battlerAtk); - u16 partnerMove = GetAllyChosenMove(); - u16 atkPartnerAbility = AI_GetAbility(battlerAtkPartner); - bool32 targetSameSide = IsTargetingPartner(battlerAtk, battlerDef); - // target partner data - u8 battlerDefPartner = BATTLE_PARTNER(battlerDef); - u16 defPartnerAbility = AI_GetAbility(battlerDefPartner); // move data + u8 atkPriority = GetMovePriority(battlerAtk, move); u16 moveEffect = gBattleMoves[move].effect; u8 moveType = gBattleMoves[move].type; u8 moveTarget = gBattleMoves[move].target; - u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, move); + u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); u8 effectiveness = AI_GetMoveEffectiveness(move); - if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HELP_PARTNER) && targetSameSide) + if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HELP_PARTNER) && AI_DATA->targetSameSide) return score; // don't consider ally presence if (!(gBattleMoves[move].target & MOVE_TARGET_USER)) @@ -2382,7 +2361,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (TestMoveFlags(move, FLAG_POWDER)) { if ((B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS)) - || defAbility == ABILITY_OVERCOAT + || AI_DATA->defAbility == ABILITY_OVERCOAT || GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_SAFETY_GOOGLES) score -= 10; } @@ -2390,9 +2369,9 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // check ground immunities if (moveType == TYPE_GROUND && !IsBattlerGrounded(battlerDef) - && ((defAbility == ABILITY_LEVITATE - && DoesBattlerIgnoreAbilityChecks(atkAbility, move)) - || defHoldEffect == HOLD_EFFECT_AIR_BALLOON + && ((AI_DATA->defAbility == ABILITY_LEVITATE + && DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) + || AI_DATA->defHoldEffect == HOLD_EFFECT_AIR_BALLOON || (gStatuses3[battlerDef] & (STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS))) && move != MOVE_THOUSAND_ARROWS) { @@ -2406,7 +2385,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // target ability checks if (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) { - switch (defAbility) + switch (AI_DATA->defAbility) { case ABILITY_VOLT_ABSORB: case ABILITY_MOTOR_DRIVE: @@ -2513,7 +2492,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case ABILITY_LEAF_GUARD: if (AI_WeatherHasEffect() && (gBattleWeather & WEATHER_SUN_ANY) - && defHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA + && AI_DATA->defHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA && IsNonVolatileStatusMoveEffect(moveEffect)) score -= 10; break; @@ -2522,14 +2501,14 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // target partner ability checks if (IsValidDoubleBattle(battlerAtk) && !IsTargetingPartner(battlerAtk, battlerDef)) { - switch (defPartnerAbility) + switch (AI_DATA->defPartnerAbility) { case ABILITY_LIGHTNING_ROD: - if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(move, atkAbility)) + if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(move, AI_DATA->atkAbility)) score -= 20; break; case ABILITY_STORM_DRAIN: - if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(move, atkAbility)) + if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(move, AI_DATA->atkAbility)) score -= 20; break; case ABILITY_MAGIC_BOUNCE: @@ -2558,7 +2537,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // ignore def ability check #if B_PRANKSTER < GEN_7 - if (atkAbility == ABILITY_PRANKSTER && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) && IS_MOVE_STATUS(move) + if (AI_DATA->atkAbility == ABILITY_PRANKSTER && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) && IS_MOVE_STATUS(move) && !(moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER))) score -= 10; #endif @@ -2600,23 +2579,23 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SLEEP: if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) score -= 10; - else if (!AI_CanPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + else if (!AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_ABSORB: - if (defAbility == ABILITY_LIQUID_OOZE) + if (AI_DATA->defAbility == ABILITY_LIQUID_OOZE) score -= 6; break; case EFFECT_STRENGTH_SAP: - if (defAbility == ABILITY_CONTRARY) + if (AI_DATA->defAbility == ABILITY_CONTRARY) score -= 10; - else if (!BattlerStatCanFall(battlerDef, defAbility, STAT_ATK)) + else if (!BattlerStatCanFall(battlerDef, AI_DATA->defAbility, STAT_ATK)) score -= 10; break; case EFFECT_EXPLOSION: if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE) { - if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(atkAbility, move)) + if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) { score -= 10; } @@ -2628,7 +2607,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (CountUsablePartyMons(battlerDef) == 2 && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) - && CanAttackerFaintTarget(battlerAtkPartner, BATTLE_PARTNER(battlerDef), *(gBattleStruct->chosenMovePositions + battlerAtkPartner))) + && CanAttackerFaintTarget(AI_DATA->battlerAtkPartner, BATTLE_PARTNER(battlerDef), *(gBattleStruct->chosenMovePositions + AI_DATA->battlerAtkPartner))) { ; // good } @@ -2658,7 +2637,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_DREAM_EATER: - if (defAbility != ABILITY_COMATOSE && !(gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) + if (AI_DATA->defAbility != ABILITY_COMATOSE && !(gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) score -= 10; break; case EFFECT_COPYCAT: @@ -2681,9 +2660,11 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_ATTACK_UP: case EFFECT_ATTACK_UP_2: - if (atkAbility != ABILITY_CONTRARY) + if (AI_DATA->atkAbility != ABILITY_CONTRARY) { - if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + if (MovesWithSplitUnusable(battlerAtk, battlerDef, SPLIT_PHYSICAL)) + score -= 8; + else if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; } else @@ -2692,7 +2673,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_ATTACK_ACCURACY_UP: //hone claws - if (atkAbility != ABILITY_CONTRARY) + if (AI_DATA->atkAbility != ABILITY_CONTRARY) { if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE && (gBattleMons[battlerAtk].statStages[STAT_ACC] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL))) @@ -2714,17 +2695,17 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_DEF)) + if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) score -= 10; } break; case EFFECT_FLOWER_SHIELD: if (!IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) - && !(IsValidDoubleBattle(battlerAtk) && IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_GRASS))) + && !(IsValidDoubleBattle(battlerAtk) && IS_BATTLER_OF_TYPE(AI_DATA->battlerAtkPartner, TYPE_GRASS))) score -= 10; break; case EFFECT_MAGNETIC_FLUX: - if (atkAbility == ABILITY_PLUS || atkAbility == ABILITY_MINUS) + if (AI_DATA->atkAbility == ABILITY_PLUS || AI_DATA->atkAbility == ABILITY_MINUS) { if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) @@ -2737,37 +2718,37 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsValidDoubleBattle(battlerAtk)) { - if (atkPartnerAbility == ABILITY_PLUS || atkPartnerAbility == ABILITY_MINUS) + if (AI_DATA->atkPartnerAbility == ABILITY_PLUS || AI_DATA->atkPartnerAbility == ABILITY_MINUS) { - if ((gBattleMons[battlerAtkPartner].statStages[STAT_DEF] >= MAX_STAT_STAGE) - && (gBattleMons[battlerAtkPartner].statStages[STAT_SPDEF] >= MAX_STAT_STAGE)) + if ((gBattleMons[AI_DATA->battlerAtkPartner].statStages[STAT_DEF] >= MAX_STAT_STAGE) + && (gBattleMons[AI_DATA->battlerAtkPartner].statStages[STAT_SPDEF] >= MAX_STAT_STAGE)) score -= 10; } - else if (atkAbility != ABILITY_PLUS && atkAbility != ABILITY_MINUS) + else if (AI_DATA->atkAbility != ABILITY_PLUS && AI_DATA->atkAbility != ABILITY_MINUS) { score -= 10; // nor our or our partner's ability is plus/minus } } break; case EFFECT_AROMATIC_MIST: - if (!IsValidDoubleBattle(battlerAtk) || gBattleMons[battlerAtkPartner].hp == 0 || !BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPDEF)) + if (!IsValidDoubleBattle(battlerAtk) || gBattleMons[AI_DATA->battlerAtkPartner].hp == 0 || !BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPDEF)) score -= 10; break; case EFFECT_SPEED_UP: case EFFECT_SPEED_UP_2: - if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPEED)) + if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) score -= 10; break; case EFFECT_SPECIAL_ATTACK_UP: case EFFECT_SPECIAL_ATTACK_UP_2: - if (atkAbility == ABILITY_CONTRARY - || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPATK) + if (AI_DATA->atkAbility == ABILITY_CONTRARY + || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) score -= 10; break; case EFFECT_GROWTH: case EFFECT_ATTACK_SPATK_UP: // work up - if (!BattlerShouldRaiseAttacks(battlerAtk, atkAbility)) + if (!BattlerShouldRaiseAttacks(battlerAtk, AI_DATA->atkAbility)) score -= 10; break; case EFFECT_ROTOTILLER: @@ -2775,29 +2756,29 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) && AI_IsBattlerGrounded(battlerAtk) - && atkAbility != ABILITY_CONTRARY - && (BattlerStatCanRise(battlerAtk, atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPATK))) - && !(IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_GRASS) - && AI_IsBattlerGrounded(battlerAtkPartner) - && atkPartnerAbility != ABILITY_CONTRARY - && (BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) - || BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)))) + && AI_DATA->atkAbility != ABILITY_CONTRARY + && (BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK))) + && !(IS_BATTLER_OF_TYPE(AI_DATA->battlerAtkPartner, TYPE_GRASS) + && AI_IsBattlerGrounded(AI_DATA->battlerAtkPartner) + && AI_DATA->atkPartnerAbility != ABILITY_CONTRARY + && (BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_ATK) + || BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPATK)))) { score -= 10; } } else if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) && AI_IsBattlerGrounded(battlerAtk) - && atkAbility != ABILITY_CONTRARY - && (BattlerStatCanRise(battlerAtk, atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPATK)))) + && AI_DATA->atkAbility != ABILITY_CONTRARY + && (BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK)))) { score -= 10; } break; case EFFECT_GEAR_UP: - if (atkAbility == ABILITY_PLUS || atkAbility == ABILITY_MINUS) + if (AI_DATA->atkAbility == ABILITY_PLUS || AI_DATA->atkAbility == ABILITY_MINUS) { - if (!BattlerShouldRaiseAttacks(battlerAtk, atkAbility)) + if (!BattlerShouldRaiseAttacks(battlerAtk, AI_DATA->atkAbility)) score -= 10; } else if (!IsValidDoubleBattle(battlerAtk)) @@ -2807,13 +2788,13 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsValidDoubleBattle(battlerAtk)) { - if (atkPartnerAbility == ABILITY_PLUS || atkPartnerAbility == ABILITY_MINUS) + if (AI_DATA->atkPartnerAbility == ABILITY_PLUS || AI_DATA->atkPartnerAbility == ABILITY_MINUS) { - if ((!BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) - && (!BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL))) + if ((!BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + && (!BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL))) score -= 10; } - else if (atkAbility != ABILITY_PLUS && atkAbility != ABILITY_MINUS) + else if (AI_DATA->atkAbility != ABILITY_PLUS && AI_DATA->atkAbility != ABILITY_MINUS) { score -= 10; // nor our or our partner's ability is plus/minus } @@ -2821,36 +2802,36 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SPECIAL_DEFENSE_UP: case EFFECT_SPECIAL_DEFENSE_UP_2: - if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPDEF)) + if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) score -= 10; break; case EFFECT_ACCURACY_UP: case EFFECT_ACCURACY_UP_2: - if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_ACC)) + if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ACC)) score -= 10; break; case EFFECT_EVASION_UP: case EFFECT_EVASION_UP_2: case EFFECT_MINIMIZE: - if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_EVASION)) + if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_EVASION)) score -= 10; break; case EFFECT_ACUPRESSURE: if (DoesSubstituteBlockMove(battlerAtk, battlerDef, move) - || AreBattlersStatsMaxed(battlerDef) || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) + || AreBattlersStatsMaxed(battlerDef) || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) score -= 10; break; case EFFECT_ATTACK_DOWN: case EFFECT_ATTACK_DOWN_2: if (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL) - || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner { score -= 10; } break; case EFFECT_VENOM_DRENCH: - if (targetSameSide) + if (AI_DATA->targetSameSide) score -= 10; if (!(gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)) @@ -2867,7 +2848,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_NOBLE_ROAR: if (((gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) && (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL))) - || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner { score -= 10; } @@ -2875,19 +2856,19 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_DEFENSE_DOWN: case EFFECT_DEFENSE_DOWN_2: if (gBattleMons[battlerDef].statStages[STAT_DEF] == MIN_STAT_STAGE - || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner score -= 10; break; case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN_2: if (gBattleMons[battlerDef].statStages[STAT_SPEED] == MIN_STAT_STAGE - || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner score -= 10; break; case EFFECT_SPECIAL_ATTACK_DOWN: case EFFECT_SPECIAL_ATTACK_DOWN_2: if (gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE - || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner score -= 10; break; case EFFECT_CAPTIVATE: @@ -2901,23 +2882,23 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SPECIAL_DEFENSE_DOWN: case EFFECT_SPECIAL_DEFENSE_DOWN_2: if (gBattleMons[battlerDef].statStages[STAT_SPDEF] == MIN_STAT_STAGE - || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner score -= 10; break; case EFFECT_ACCURACY_DOWN: case EFFECT_ACCURACY_DOWN_2: if (gBattleMons[battlerDef].statStages[STAT_ACC] == MIN_STAT_STAGE - || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner score -= 10; break; case EFFECT_EVASION_DOWN: case EFFECT_EVASION_DOWN_2: if (gBattleMons[battlerDef].statStages[STAT_EVASION] == MIN_STAT_STAGE - || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner score -= 10; break; case EFFECT_HAZE: - if (PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + if (PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) { score -= 10; // partner already using haze } @@ -2926,12 +2907,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u32 i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { - if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) + if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) 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[battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) + if (gBattleMons[battlerDef].statStages[i] < DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) score -= 10; //Don't want to reset enemy lowered stats } } @@ -2943,7 +2924,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_ROAR: - if (DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; // don't scare away pokemon twice //Don't blow out a Pokemon that'll faint soon or is taking a a lot of secondary damage @@ -2953,12 +2934,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; if (CountUsablePartyMons(battlerDef) == 1 - || defAbility == ABILITY_SUCTION_CUPS + || AI_DATA->defAbility == ABILITY_SUCTION_CUPS || gStatuses3[battlerDef] & STATUS3_ROOTED) score -= 10; break; case EFFECT_HIT_SWITCH_TARGET: - if (DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; // don't scare away pokemon twice else if (GetHealthPercentage(battlerDef) < 10 && BattlerHasSecondaryDamage(battlerDef)) score -= 10; // don't blow away mon that will faint soon @@ -2981,7 +2962,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_PURIFY: if (!(gBattleMons[battlerDef].status1 & STATUS1_ANY)) score -= 10; - else if (battlerDef == battlerAtkPartner) + else if (battlerDef == AI_DATA->battlerAtkPartner) break; //Always heal your ally else if (GetHealthPercentage(battlerAtk) == 100) score -= 10; @@ -2989,33 +2970,33 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 8; //No point in healing, but should at least do it if nothing better break; case EFFECT_TOXIC_THREAD: - if (gBattleMons[battlerDef].statStages[STAT_SPEED] > MIN_STAT_STAGE && defAbility != ABILITY_CONTRARY) + if (gBattleMons[battlerDef].statStages[STAT_SPEED] > MIN_STAT_STAGE && AI_DATA->defAbility != ABILITY_CONTRARY) score -= 10; //fallthrough case EFFECT_POISON: case EFFECT_TOXIC: - if (!AI_CanPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; else if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) score -= 10; break; case EFFECT_LIGHT_SCREEN: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_LIGHTSCREEN - || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; else if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL) score--; //can use move, but it doesn't stack with light screen break; case EFFECT_REFLECT: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_REFLECT - || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; else if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL) score--; // can use, but doesn't stack with reflect break; case EFFECT_AURORA_VEIL: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL - || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) || !(gBattleWeather & WEATHER_HAIL_ANY)) score -= 10; else if (gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN)) @@ -3024,16 +3005,16 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_OHKO: if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) score -= 10; - if (!ShouldTryOHKO(battlerAtk, battlerDef, atkAbility, defAbility, accuracy, move)) + if (!ShouldTryOHKO(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, accuracy, move)) score -= 10; break; case EFFECT_RECOIL_IF_MISS: - if (atkAbility != ABILITY_MAGIC_GUARD && accuracy < 75) + if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && accuracy < 75) score -= 6; break; case EFFECT_MIST: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST - || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_FOCUS_ENERGY: @@ -3041,7 +3022,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_RECOIL_25: - if (atkAbility != ABILITY_MAGIC_GUARD && atkAbility != ABILITY_ROCK_HEAD) + if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && AI_DATA->atkAbility != ABILITY_ROCK_HEAD) { u32 recoilDmg = max(1, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 4); if (!ShouldUseRecoilMove(battlerAtk, battlerDef, recoilDmg, AI_THINKING_STRUCT->movesetIndex)) @@ -3051,7 +3032,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_RECOIL_33: case EFFECT_RECOIL_33_STATUS: - if (atkAbility != ABILITY_MAGIC_GUARD && atkAbility != ABILITY_ROCK_HEAD) + if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && AI_DATA->atkAbility != ABILITY_ROCK_HEAD) { u32 recoilDmg = max(1, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 3); if (!ShouldUseRecoilMove(battlerAtk, battlerDef, recoilDmg, AI_THINKING_STRUCT->movesetIndex)) @@ -3060,7 +3041,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_RECOIL_50: - if (atkAbility != ABILITY_MAGIC_GUARD && atkAbility != ABILITY_ROCK_HEAD) + if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && AI_DATA->atkAbility != ABILITY_ROCK_HEAD) { u32 recoilDmg = max(1, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 2); if (!ShouldUseRecoilMove(battlerAtk, battlerDef, recoilDmg, AI_THINKING_STRUCT->movesetIndex)) @@ -3069,18 +3050,18 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_CONFUSE: - if (!AI_CanConfuse(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + if (!AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_TEETER_DANCE: if (((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) - || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && defAbility == ABILITY_OWN_TEMPO) + || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && AI_DATA->defAbility == ABILITY_OWN_TEMPO) || (IsBattlerGrounded(battlerDef) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) || (DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) - && ((gBattleMons[battlerDefPartner].status2 & STATUS2_CONFUSION) - || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && defPartnerAbility == ABILITY_OWN_TEMPO) - || (IsBattlerGrounded(battlerDefPartner) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) - || (DoesSubstituteBlockMove(battlerAtk, battlerDefPartner, move)))) + && ((gBattleMons[AI_DATA->battlerDefPartner].status2 & STATUS2_CONFUSION) + || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && AI_DATA->defPartnerAbility == ABILITY_OWN_TEMPO) + || (IsBattlerGrounded(AI_DATA->battlerDefPartner) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + || (DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, move)))) { score -= 10; } @@ -3093,23 +3074,23 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_PARALYZE: if (move != MOVE_GLARE && gMoveResultFlags & MOVE_RESULT_NO_EFFECT) score -= 10; - else if (AI_CanParalyze(battlerAtk, battlerDef, defAbility, move, partnerMove)) + else if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_TWO_TURNS_ATTACK: - if (atkHoldEffect != HOLD_EFFECT_POWER_HERB && CanTargetFaintAi(battlerDef, battlerAtk)) + if (AI_DATA->atkHoldEffect != HOLD_EFFECT_POWER_HERB && CanTargetFaintAi(battlerDef, battlerAtk)) score -= 6; break; case EFFECT_SUBSTITUTE: if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE || GetHealthPercentage(battlerAtk) <= 25 - || defAbility == ABILITY_INFILTRATOR) + || AI_DATA->defAbility == ABILITY_INFILTRATOR) score -= 10; else if (B_SOUND_SUBSTITUTE >= GEN_6 && TestMoveFlagsInMoveset(battlerDef, FLAG_SOUND)) score -= 10; break; case EFFECT_RECHARGE: - if (atkAbility != ABILITY_TRUANT + if (AI_DATA->atkAbility != ABILITY_TRUANT && !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex)) score -= 2; break; @@ -3128,14 +3109,14 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_LEECH_SEED: if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || gStatuses3[battlerDef] & STATUS3_LEECHSEED - || defAbility == ABILITY_LIQUID_OOZE - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + || AI_DATA->defAbility == ABILITY_LIQUID_OOZE + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_DISABLE: if (gDisableStructs[battlerDef].disableTimer == 0 - && (B_MENTAL_HERB >= GEN_5 && defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) - && !PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) + && !PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) { if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first { @@ -3154,13 +3135,13 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) //TODO - predicted move /*if (GetBattleMoveSplit(predictedMove) == SPLIT_STATUS || predictedMove == MOVE_NONE - || DoesSubstituteBlockMove(battlerAtk, battlerDefPartner, predictedMove) + || DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, predictedMove) score -= 10;*/ break; case EFFECT_ENCORE: if (gDisableStructs[battlerDef].encoreTimer == 0 - && (B_MENTAL_HERB >= GEN_5 && defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) - && !DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) + && !DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) { if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first { @@ -3186,9 +3167,9 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SLEEP_TALK: // AI shouldn't really know if its about to wake up since its random /*if (((gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) == 1 || !(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP)) - && atkAbility != ABILITY_COMATOSE) + && AI_DATA->atkAbility != ABILITY_COMATOSE) score -= 10;*/ - if (!(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) && atkAbility != ABILITY_COMATOSE) + if (!(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) && AI_DATA->atkAbility != ABILITY_COMATOSE) score -= 10; break; case EFFECT_CONVERSION_2: @@ -3196,15 +3177,15 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_LOCK_ON: if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS - || atkAbility == ABILITY_NO_GUARD - || defAbility == ABILITY_NO_GUARD - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + || AI_DATA->atkAbility == ABILITY_NO_GUARD + || AI_DATA->defAbility == ABILITY_NO_GUARD + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_LASER_FOCUS: if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS) score -= 10; - else if (defAbility == ABILITY_SHELL_ARMOR || defAbility == ABILITY_BATTLE_ARMOR) + else if (AI_DATA->defAbility == ABILITY_SHELL_ARMOR || AI_DATA->defAbility == ABILITY_BATTLE_ARMOR) score -= 8; break; case EFFECT_SKETCH: @@ -3219,36 +3200,36 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // TODO break; case EFFECT_HEAL_BELL: - if (!AnyPartyMemberStatused(battlerAtk, TestMoveFlags(move, FLAG_SOUND)) || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + if (!AnyPartyMemberStatused(battlerAtk, TestMoveFlags(move, FLAG_SOUND)) || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_MEAN_LOOK: if (IsBattlerTrapped(battlerDef, TRUE) - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_HIT_PREVENT_ESCAPE: break; case EFFECT_NIGHTMARE: if (gBattleMons[battlerDef].status2 & STATUS2_NIGHTMARE - || !(gBattleMons[battlerDef].status1 & STATUS1_SLEEP || defAbility == ABILITY_COMATOSE) - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + || !(gBattleMons[battlerDef].status1 & STATUS1_SLEEP || AI_DATA->defAbility == ABILITY_COMATOSE) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_CURSE: if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) { if (gBattleMons[battlerDef].status2 & STATUS2_CURSED - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; else if (GetHealthPercentage(battlerAtk) <= 50) score -= 6; } else //Regular Curse { - if (!BattlerStatCanRise(battlerAtk, atkAbility, STAT_ATK) - && !BattlerStatCanRise(battlerAtk, atkAbility, STAT_DEF) - && !BattlerStatCanFall(battlerAtk, atkAbility, STAT_SPEED)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) + && !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF) + && !BattlerStatCanFall(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) score -= 10; } break; @@ -3293,8 +3274,8 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && move != MOVE_CRAFTY_SHIELD) //These moves have infinite usage { if (BattlerHasSecondaryDamage(battlerAtk) - && defAbility != ABILITY_MOXIE - && defAbility != ABILITY_BEAST_BOOST) + && AI_DATA->defAbility != ABILITY_MOXIE + && AI_DATA->defAbility != ABILITY_BEAST_BOOST) { score -= 10; //Don't protect if you're going to faint after protecting } @@ -3325,25 +3306,25 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SPIKES: if (gSideTimers[GetBattlerSide(battlerDef)].spikesAmount >= 3) score -= 10; - else if (PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove) + else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].spikesAmount == 2) 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(battlerAtkPartner, move, partnerMove)) //Only one mon needs to set up Stealth Rocks + || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) //Only one mon needs to set up Stealth Rocks score -= 10; break; case EFFECT_TOXIC_SPIKES: if (gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount >= 2) score -= 10; - else if (PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount == 1) + else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount == 1) 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) score -= 10; - else if (PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) + else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) score -= 10; //Only one mon needs to set up Sticky Web break; case EFFECT_FORESIGHT: @@ -3353,7 +3334,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) { score -= 9; } @@ -3364,15 +3345,15 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)) - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 9; break; case EFFECT_PERISH_SONG: if (IsValidDoubleBattle(battlerAtk)) { if (CountUsablePartyMons(battlerAtk) <= 2 - && atkAbility != ABILITY_SOUNDPROOF - && atkPartnerAbility != ABILITY_SOUNDPROOF + && AI_DATA->atkAbility != ABILITY_SOUNDPROOF + && AI_DATA->atkPartnerAbility != ABILITY_SOUNDPROOF && CountUsablePartyMons(FOE(battlerAtk)) >= 3) { score -= 10; //Don't wipe your team if you're going to lose @@ -3384,12 +3365,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { score -= 10; //Both enemies are perish songed } - else if (DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + else if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; } else { - if (CountUsablePartyMons(battlerAtk) == 1 && atkAbility != ABILITY_SOUNDPROOF + if (CountUsablePartyMons(battlerAtk) == 1 && AI_DATA->atkAbility != ABILITY_SOUNDPROOF && CountUsablePartyMons(battlerDef) >= 2) score -= 10; @@ -3399,42 +3380,42 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SANDSTORM: if (gBattleWeather & WEATHER_SANDSTORM_ANY //TODO | WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(battlerAtkPartner, partnerMove)) + || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SUNNY_DAY: if (gBattleWeather & WEATHER_SUN_ANY //TODO | WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(battlerAtkPartner, partnerMove)) + || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_RAIN_DANCE: if (gBattleWeather & WEATHER_RAIN_ANY //TODO | WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(battlerAtkPartner, partnerMove)) + || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_HAIL: if (gBattleWeather & WEATHER_HAIL_ANY //TODO | WEATHER_PRIMAL_ANY | WEATHER_CIRCUS) - || PartnerMoveEffectIsWeather(battlerAtkPartner, partnerMove)) + || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SWAGGER: - if (targetSameSide && defAbility == ABILITY_CONTRARY) + if (AI_DATA->targetSameSide && AI_DATA->defAbility == ABILITY_CONTRARY) score -= 10; - else if (!AI_CanConfuse(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + else if (!AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_ATTRACT: { u8 atkGender = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerAtk].species, gBattleMons[battlerAtk].personality); u8 defGender = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerDef].species, gBattleMons[battlerDef].personality); - if (!AI_CanBeInfatuated(battlerAtk, battlerDef, defAbility, atkGender, defGender) - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + if (!AI_CanBeInfatuated(battlerAtk, battlerDef, AI_DATA->defAbility, atkGender, defGender) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; } break; case EFFECT_SAFEGUARD: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_SAFEGUARD - || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_BURN_UP: @@ -3469,7 +3450,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || gSideTimers[GetBattlerSide(battlerDef)].auroraVeilTimer != 0 || gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_HAZARDS_ANY) { - if (PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + if (PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) { score -= 10; //Only need one hazards removal break; @@ -3484,8 +3465,8 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsValidDoubleBattle(battlerAtk)) { - if (IsHazardMoveEffect(gBattleMoves[partnerMove].effect) // partner is going to set up hazards - && GetWhoStrikesFirst(battlerAtkPartner, battlerAtk, FALSE)) // partner is going to set up before the potential Defog + if (IsHazardMoveEffect(gBattleMoves[AI_DATA->partnerMove].effect) // partner is going to set up hazards + && GetWhoStrikesFirst(AI_DATA->battlerAtkPartner, battlerAtk, FALSE)) // partner is going to set up before the potential Defog { score -= 10; break; // Don't use Defog if partner is going to set up hazards @@ -3494,11 +3475,11 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // evasion check if (gBattleMons[battlerDef].statStages[STAT_EVASION] == MIN_STAT_STAGE - || ((defAbility == ABILITY_CONTRARY) && !targetSameSide)) // don't want to raise target stats unless its your partner + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner score -= 10; break; case EFFECT_BELLY_DRUM: - if (atkAbility == ABILITY_CONTRARY) + if (AI_DATA->atkAbility == ABILITY_CONTRARY) score -= 10; else if (GetHealthPercentage(battlerAtk) <= 60) score -= 10; @@ -3508,12 +3489,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u32 i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { - if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) + if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) 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[battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) + if (gBattleMons[battlerDef].statStages[i] < DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) score -= 10; //Don't want to copy enemy lowered stats } } @@ -3525,8 +3506,8 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_SOLARBEAM: - if (atkHoldEffect == HOLD_EFFECT_POWER_HERB - || (AI_WeatherHasEffect() && gBattleWeather & WEATHER_SUN_ANY && atkHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA)) + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_POWER_HERB + || (AI_WeatherHasEffect() && gBattleWeather & WEATHER_SUN_ANY && AI_DATA->atkHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA)) break; if (CanTargetFaintAi(battlerDef, battlerAtk)) //Attacker can be knocked out score -= 4; @@ -3538,7 +3519,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && gBattleMoves[predictedMove].effect == EFFECT_SEMI_INVULNERABLE) score -= 10;*/ // Don't Fly if opponent is going to fly after you - if (BattlerWillFaintFromWeather(battlerAtk, atkAbility) + if (BattlerWillFaintFromWeather(battlerAtk, AI_DATA->atkAbility) && (move == MOVE_FLY || move == MOVE_BOUNCE)) score -= 10; // Attacker will faint while in the air break; @@ -3550,7 +3531,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (move == MOVE_FAKE_OUT) { - if ((atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || atkAbility == ABILITY_GORILLA_TACTICS) + if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || AI_DATA->atkAbility == ABILITY_GORILLA_TACTICS) && (CountUsablePartyMons(battlerDef) >= 2 || !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex))) { if (CountUsablePartyMons(battlerAtk) == 1) @@ -3583,39 +3564,39 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_TORMENT: if (gBattleMons[battlerDef].status2 & STATUS2_TORMENT - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) { score -= 10; break; } - if (B_MENTAL_HERB >= GEN_5 && defHoldEffect == HOLD_EFFECT_CURE_ATTRACT) + if (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect == HOLD_EFFECT_CURE_ATTRACT) score -= 6; break; case EFFECT_FLATTER: - if (targetSameSide && defAbility == ABILITY_CONTRARY) + if (AI_DATA->targetSameSide && AI_DATA->defAbility == ABILITY_CONTRARY) score -= 10; - else if (!AI_CanConfuse(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + else if (!AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_WILL_O_WISP: - if (!AI_CanBurn(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + if (!AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_MEMENTO: - if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; else if (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE && gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE) score -= 10; break; case EFFECT_HEALING_WISH: //healing wish, lunar dance - if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; else if (IsPartyFullyHealedExceptBattler(battlerAtk)) score -= 10; break; case EFFECT_FINAL_GAMBIT: - if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_FOCUS_PUNCH: @@ -3639,27 +3620,27 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC)) { - if (atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, atkAbility, STAT_SPDEF)) + if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) score -= 10; } break; case EFFECT_TAUNT: if (gDisableStructs[battlerDef].tauntTimer > 0 - || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score--; break; case EFFECT_FOLLOW_ME: case EFFECT_HELPING_HAND: if (!IsValidDoubleBattle(battlerAtk) - || !IsBattlerAlive(battlerAtkPartner) - || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove) - || (partnerMove != MOVE_NONE && IS_MOVE_STATUS(partnerMove)) - || *(gBattleStruct->monToSwitchIntoId + battlerAtkPartner) != PARTY_SIZE) //Partner is switching out. + || !IsBattlerAlive(AI_DATA->battlerAtkPartner) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) + || (AI_DATA->partnerMove != MOVE_NONE && IS_MOVE_STATUS(AI_DATA->partnerMove)) + || *(gBattleStruct->monToSwitchIntoId + AI_DATA->battlerAtkPartner) != PARTY_SIZE) //Partner is switching out. score -= 10; break; case EFFECT_TRICK: - if ((atkHoldEffect == HOLD_EFFECT_NONE && defHoldEffect == HOLD_EFFECT_NONE) - || defAbility == ABILITY_STICKY_HOLD + if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_NONE && AI_DATA->defHoldEffect == HOLD_EFFECT_NONE) + || AI_DATA->defAbility == ABILITY_STICKY_HOLD || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item) || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerDef].item) || !CanBattlerGetOrLoseItem(battlerDef, gBattleMons[battlerAtk].item) @@ -3667,15 +3648,15 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; // kinda cheating with battlerDef item check, but only item effects recorded break; case EFFECT_BESTOW: - if (atkHoldEffect == HOLD_EFFECT_NONE + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_NONE || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item)) // AI knows its own item score -= 10; break; case EFFECT_ROLE_PLAY: - if (atkAbility == defAbility - || defAbility == ABILITY_NONE - || IsRolePlayBannedAbilityAtk(atkAbility) - || IsRolePlayBannedAbility(defAbility)) + if (AI_DATA->atkAbility == AI_DATA->defAbility + || AI_DATA->defAbility == ABILITY_NONE + || IsRolePlayBannedAbilityAtk(AI_DATA->atkAbility) + || IsRolePlayBannedAbility(AI_DATA->defAbility)) score -= 10; break; case EFFECT_WISH: @@ -3715,46 +3696,46 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_YAWN: if (gStatuses3[battlerDef] & STATUS3_YAWN) score -= 10; - else if (!AI_CanPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + else if (!AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_KNOCK_OFF: - /*if (defHoldEffect == HOLD_EFFECT_ASSAULT_VEST - || (defHoldEffect == HOLD_EFFECT_CHOICE_BAND && atkAbility != ABILITY_GORILLA_TACTICS && gBattleStruct->choicedMove[battlerDef])) + /*if (AI_DATA->defHoldEffect == HOLD_EFFECT_ASSAULT_VEST + || (AI_DATA->defHoldEffect == HOLD_EFFECT_CHOICE_BAND && AI_DATA->atkAbility != ABILITY_GORILLA_TACTICS && gBattleStruct->choicedMove[battlerDef])) { if (GetStrongestMove(battlerDef, battlerAtk) == MOVE_NONE || AI_SpecialTypeCalc(GetStrongestMove(battlerDef, battlerAtk), battlerDef, battlerAtk) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) DECREASE_VIABILITY(9); //Don't use Knock Off is the enemy's only moves don't affect the AI }*/ - if (defHoldEffect == HOLD_EFFECT_NONE) + if (AI_DATA->defHoldEffect == HOLD_EFFECT_NONE) score -= 4; break; case EFFECT_SKILL_SWAP: - if (atkAbility == ABILITY_NONE || defAbility == ABILITY_NONE - || IsSkillSwapBannedAbility(atkAbility) || IsSkillSwapBannedAbility(defAbility)) + if (AI_DATA->atkAbility == ABILITY_NONE || AI_DATA->defAbility == ABILITY_NONE + || IsSkillSwapBannedAbility(AI_DATA->atkAbility) || IsSkillSwapBannedAbility(AI_DATA->defAbility)) score -= 10; break; case EFFECT_WORRY_SEED: - if (defAbility == ABILITY_INSOMNIA - || IsWorrySeedBannedAbility(defAbility)) + if (AI_DATA->defAbility == ABILITY_INSOMNIA + || IsWorrySeedBannedAbility(AI_DATA->defAbility)) score -= 10; break; case EFFECT_GASTRO_ACID: if (gStatuses3[battlerDef] & STATUS3_GASTRO_ACID - || IsGastroAcidBannedAbility(defAbility)) + || IsGastroAcidBannedAbility(AI_DATA->defAbility)) score -= 10; break; case EFFECT_ENTRAINMENT: - if (atkAbility == ABILITY_NONE - || IsEntrainmentBannedAbilityAttacker(atkAbility) - || IsEntrainmentTargetOrSimpleBeamBannedAbility(defAbility)) + if (AI_DATA->atkAbility == ABILITY_NONE + || IsEntrainmentBannedAbilityAttacker(AI_DATA->atkAbility) + || IsEntrainmentTargetOrSimpleBeamBannedAbility(AI_DATA->defAbility)) score -= 10; break; case EFFECT_CORE_ENFORCER: break; case EFFECT_SIMPLE_BEAM: - if (defAbility == ABILITY_SIMPLE - || IsEntrainmentTargetOrSimpleBeamBannedAbility(defAbility)) + if (AI_DATA->defAbility == ABILITY_SIMPLE + || IsEntrainmentTargetOrSimpleBeamBannedAbility(AI_DATA->defAbility)) score -= 10; break; case EFFECT_IMPRISON: @@ -3766,41 +3747,41 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_PSYCHO_SHIFT: - if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_CanPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; - else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && !AI_CanBurn(battlerAtk, battlerDef, defAbility, battlerAtkPartner, move, partnerMove)) + else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && !AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; - else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, defAbility, move, partnerMove)) + else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; - else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_CanPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; else score -= 10; break; case EFFECT_SNATCH: if (!TestMoveFlagsInMoveset(battlerDef, FLAG_SNATCH_AFFECTED) - || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_MUD_SPORT: if (gFieldStatuses & STATUS_FIELD_MUDSPORT - || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_WATER_SPORT: if (gFieldStatuses & STATUS_FIELD_WATERSPORT - || PartnerHasSameMoveEffectWithoutTarget(battlerAtkPartner, move, partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_TICKLE: - if ((defAbility == ABILITY_CONTRARY) && !targetSameSide) + if ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide) score -= 10; else if ((gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) && gBattleMons[battlerDef].statStages[STAT_DEF] == MIN_STAT_STAGE) score -= 10; break; case EFFECT_COSMIC_POWER: - if (atkAbility == ABILITY_CONTRARY) + if (AI_DATA->atkAbility == ABILITY_CONTRARY) score -= 10; else if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) @@ -3820,14 +3801,14 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break;*/ case EFFECT_BULK_UP: - if (atkAbility == ABILITY_CONTRARY) + if (AI_DATA->atkAbility == ABILITY_CONTRARY) score -= 10; else if ((gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) && gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE) score -= 10; break; case EFFECT_COIL: - if (atkAbility == ABILITY_CONTRARY) + if (AI_DATA->atkAbility == ABILITY_CONTRARY) score -= 10; else if (gBattleMons[battlerAtk].statStages[STAT_ACC] >= MAX_STAT_STAGE && (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) @@ -3835,7 +3816,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_CALM_MIND: - if (atkAbility == ABILITY_CONTRARY) + if (AI_DATA->atkAbility == ABILITY_CONTRARY) score -= 10; else if ((gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) @@ -3843,7 +3824,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_QUIVER_DANCE: case EFFECT_GEOMANCY: - if (atkAbility == ABILITY_CONTRARY) + if (AI_DATA->atkAbility == ABILITY_CONTRARY) score -= 10; else if (gBattleMons[battlerAtk].statStages[STAT_SPEED] >= MAX_STAT_STAGE && (gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) @@ -3852,14 +3833,14 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_DRAGON_DANCE: case EFFECT_SHIFT_GEAR: - if (atkAbility == ABILITY_CONTRARY) + if (AI_DATA->atkAbility == ABILITY_CONTRARY) score -= 10; else if ((gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) && (gBattleMons[battlerAtk].statStages[STAT_SPEED] >= MAX_STAT_STAGE)) score -= 10; break; case EFFECT_SHELL_SMASH: - if (atkAbility == ABILITY_CONTRARY) + if (AI_DATA->atkAbility == ABILITY_CONTRARY) { if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) @@ -3875,27 +3856,27 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_POWER_TRICK: - if (targetSameSide) + if (AI_DATA->targetSameSide) score -= 10; else if (gBattleMons[battlerAtk].defense >= gBattleMons[battlerAtk].attack && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; break; case EFFECT_POWER_SWAP: // Don't use if attacker's stat stages are higher than opponents - if (targetSameSide) + if (AI_DATA->targetSameSide) score -= 10; else if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= gBattleMons[battlerDef].statStages[STAT_ATK] && gBattleMons[battlerAtk].statStages[STAT_SPATK] >= gBattleMons[battlerDef].statStages[STAT_SPATK]) score -= 10; break; case EFFECT_GUARD_SWAP: // Don't use if attacker's stat stages are higher than opponents - if (targetSameSide) + if (AI_DATA->targetSameSide) score -= 10; else if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= gBattleMons[battlerDef].statStages[STAT_DEF] && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= gBattleMons[battlerDef].statStages[STAT_SPDEF]) score -= 10; break; case EFFECT_SPEED_SWAP: - if (targetSameSide) + if (AI_DATA->targetSameSide) { score -= 10; } @@ -3908,7 +3889,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_HEART_SWAP: - if (targetSameSide) + if (AI_DATA->targetSameSide) { score -= 10; } @@ -3925,7 +3906,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_POWER_SPLIT: - if (targetSameSide) + if (AI_DATA->targetSameSide) { score -= 10; } @@ -3942,7 +3923,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_GUARD_SPLIT: - if (targetSameSide) + if (AI_DATA->targetSameSide) { score -= 10; } @@ -3971,42 +3952,42 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10;*/ break; case EFFECT_NATURAL_GIFT: - if (atkAbility == ABILITY_KLUTZ + if (AI_DATA->atkAbility == ABILITY_KLUTZ || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || GetPocketByItemId(gBattleMons[battlerAtk].item) != POCKET_BERRIES) score -= 10; break; case EFFECT_GRASSY_TERRAIN: - if (PartnerMoveEffectIsTerrain(battlerAtkPartner, partnerMove) || gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) + if (PartnerMoveEffectIsTerrain(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) score -= 10; break; case EFFECT_ELECTRIC_TERRAIN: - if (PartnerMoveEffectIsTerrain(battlerAtkPartner, partnerMove) || gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + if (PartnerMoveEffectIsTerrain(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) score -= 10; break; case EFFECT_PSYCHIC_TERRAIN: - if (PartnerMoveEffectIsTerrain(battlerAtkPartner, partnerMove) || gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + if (PartnerMoveEffectIsTerrain(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) score -= 10; break; case EFFECT_MISTY_TERRAIN: - if (PartnerMoveEffectIsTerrain(battlerAtkPartner, partnerMove) || gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + if (PartnerMoveEffectIsTerrain(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) score -= 10; break; case EFFECT_PLEDGE: - if (IsValidDoubleBattle(battlerAtk) && gBattleMons[battlerAtkPartner].hp > 0) + if (IsValidDoubleBattle(battlerAtk) && gBattleMons[AI_DATA->battlerAtkPartner].hp > 0) { - if (partnerMove != MOVE_NONE - && gBattleMoves[partnerMove].effect == EFFECT_PLEDGE - && move != partnerMove) // Different pledge moves + if (AI_DATA->partnerMove != MOVE_NONE + && gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_PLEDGE + && move != AI_DATA->partnerMove) // Different pledge moves { - if (gBattleMons[battlerAtkPartner].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) - // && gBattleMons[battlerAtkPartner].status1 != 1) // Will wake up this turn - how would AI know + if (gBattleMons[AI_DATA->battlerAtkPartner].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) + // && gBattleMons[AI_DATA->battlerAtkPartner].status1 != 1) // Will wake up this turn - how would AI know score -= 10; // Don't use combo move if your partner will cause failure } } break; case EFFECT_TRICK_ROOM: - if (PartnerMoveIs(battlerAtkPartner, partnerMove, MOVE_TRICK_ROOM)) + if (PartnerMoveIs(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove, MOVE_TRICK_ROOM)) { score -= 10; } @@ -4022,23 +4003,23 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_MAGIC_ROOM: - if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_WONDER_ROOM: - if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_GRAVITY: if ((gFieldStatuses & STATUS_FIELD_GRAVITY && !IS_BATTLER_OF_TYPE(battlerAtk, TYPE_FLYING) - && atkHoldEffect != HOLD_EFFECT_AIR_BALLOON) // Should revert Gravity in this case - || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + && AI_DATA->atkHoldEffect != HOLD_EFFECT_AIR_BALLOON) // Should revert Gravity in this case + || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_ION_DELUGE: if (gFieldStatuses & STATUS_FIELD_ION_DELUGE - || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; //TODO @@ -4054,19 +4035,19 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) switch (effect) { case MOVE_EFFECT_BURN: - if (!AI_CanBurn(battlerAtk, battlerDef, battlerAtkPartner, move, partnerMove)) + if (!AI_CanBurn(battlerAtk, battlerDef, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_EFFECT_PARALYSIS: - if (!AI_CanParalyze(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (!AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_EFFECT_POISON: - if (!AI_CanPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_EFFECT_TOXIC: - if (!AI_CanPoison(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_EFFECT_FREEZE: @@ -4078,34 +4059,34 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_EMBARGO: - if (defAbility == ABILITY_KLUTZ + if (AI_DATA->defAbility == ABILITY_KLUTZ || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || gDisableStructs[battlerDef].embargoTimer != 0 - || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_POWDER: if (!HasMoveWithType(battlerDef, TYPE_FIRE) - || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_TELEKINESIS: if (gStatuses3[battlerDef] & (STATUS3_TELEKINESIS | STATUS3_ROOTED | STATUS3_SMACKED_DOWN) || gFieldStatuses & STATUS_FIELD_GRAVITY - || defHoldEffect == HOLD_EFFECT_IRON_BALL + || AI_DATA->defHoldEffect == HOLD_EFFECT_IRON_BALL || IsTelekinesisBannedSpecies(gBattleMons[battlerDef].species) - || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_THROAT_CHOP: break; case EFFECT_HEAL_BLOCK: if (gDisableStructs[battlerDef].healBlockTimer != 0 - || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SOAK: - if (PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove) + if (PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove) || (gBattleMons[battlerDef].type1 == TYPE_WATER && gBattleMons[battlerDef].type2 == TYPE_WATER && gBattleMons[battlerDef].type3 == TYPE_MYSTERY)) @@ -4115,17 +4096,17 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) switch (move) { case MOVE_TRICK_OR_TREAT: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_FORESTS_CURSE: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; } break; case EFFECT_HIT_ENEMY_HEAL_ALLY: // pollen puff - if (targetSameSide) + if (AI_DATA->targetSameSide) { if (GetHealthPercentage(battlerDef) == 100) score -= 10; @@ -4135,7 +4116,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // fallthrough case EFFECT_HEAL_PULSE: // and floral healing - if (!targetSameSide) // Don't heal enemies + if (!AI_DATA->targetSameSide) // Don't heal enemies { score -= 10; } @@ -4150,17 +4131,17 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_ELECTRIFY: if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 //|| GetMoveTypeSpecial(battlerDef, predictedMove) == TYPE_ELECTRIC // Move will already be electric type - || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_TOPSY_TURVY: - if (!targetSameSide) + if (!AI_DATA->targetSameSide) { u8 targetPositiveStages = CountPositiveStatStages(battlerDef); u8 targetNegativeStages = CountNegativeStatStages(battlerDef); if (targetPositiveStages == 0 //No good stat changes to make bad - || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; else if (targetNegativeStages < targetPositiveStages) @@ -4168,7 +4149,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_FAIRY_LOCK: - if ((gFieldStatuses & STATUS_FIELD_FAIRY_LOCK) || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + if ((gFieldStatuses & STATUS_FIELD_FAIRY_LOCK) || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_DO_NOTHING: @@ -4191,13 +4172,13 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) #endif || (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF) || gBattleMons[battlerDef].status2 & STATUS2_MULTIPLETURNS - || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) { score -= 10; } else if (IsValidDoubleBattle(battlerAtk)) { - if (!targetSameSide) + if (!AI_DATA->targetSameSide) score -= 10; } else @@ -4218,14 +4199,14 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_QUASH: if (!IsValidDoubleBattle(battlerAtk) || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 - || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_AFTER_YOU: - if (!targetSameSide + if (!AI_DATA->targetSameSide || !IsValidDoubleBattle(battlerAtk) || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 - || PartnerMoveIsSameAsAttacker(battlerAtkPartner, battlerDef, move, partnerMove)) + || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SUCKER_PUNCH: @@ -4242,19 +4223,19 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_TAILWIND: if (gSideTimers[GetBattlerSide(battlerAtk)].tailwindTimer != 0 - || PartnerMoveIs(battlerAtkPartner, partnerMove, MOVE_TAILWIND) + || PartnerMoveIs(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove, MOVE_TAILWIND) || (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1)) // Trick Room active and not ending this turn score -= 10; break; case EFFECT_LUCKY_CHANT: if (gSideTimers[GET_BATTLER_SIDE(battlerAtk)].luckyChantTimer != 0 - || PartnerMoveIsSameNoTarget(battlerAtkPartner, move, partnerMove)) + || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_MAGNET_RISE: if (gFieldStatuses & STATUS_FIELD_GRAVITY || gDisableStructs[battlerAtk].magnetRiseTimer != 0 - || atkHoldEffect == HOLD_EFFECT_IRON_BALL + || AI_DATA->atkHoldEffect == HOLD_EFFECT_IRON_BALL || gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_MAGNET_RISE | STATUS3_SMACKED_DOWN) || !IsBattlerGrounded(battlerAtk)) score -= 10; @@ -4273,13 +4254,13 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; if (WillFaintFromWeather(battlerAtk) || MoveBlockedBySubstitute(move, battlerAtk, battlerDef) - || GetSpeciesWeight(gBattleMons[battlerDef].species, defAbility, defHoldEffect, battlerDef, TRUE) >= 2000) //200.0 kg + || GetSpeciesWeight(gBattleMons[battlerDef].species, AI_DATA->defAbility, AI_DATA->defHoldEffect, battlerDef, TRUE) >= 2000) //200.0 kg score -= 10; break; */ case EFFECT_SYNCHRONOISE: //Check holding ring target or is of same type - if (defHoldEffect == HOLD_EFFECT_RING_TARGET + if (AI_DATA->defHoldEffect == HOLD_EFFECT_RING_TARGET || IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type1) || IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type2) || IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type3)) @@ -4305,8 +4286,8 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // helping hand check - if (IsValidDoubleBattle(battlerAtk) && partnerMove != MOVE_NONE - && gBattleMoves[partnerMove].effect == EFFECT_HELPING_HAND + if (IsValidDoubleBattle(battlerAtk) && AI_DATA->partnerMove != MOVE_NONE + && gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_HELPING_HAND && IS_MOVE_STATUS(move)) score -= 10; //Don't use a status move if partner wants to help @@ -4365,22 +4346,14 @@ static u8 AI_CheckPartner(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { - bool32 targetSameSide = IsTargetingPartner(battlerAtk, battlerDef); - // attacker data - u16 atkAbility = AI_GetAbility(battlerAtk); - // target data - u16 defAbility = AI_GetAbility(battlerDef); - // attacker partner data - u8 battlerAtkPartner = BATTLE_PARTNER(battlerAtk); - u16 partnerMove = GetAllyChosenMove(); // move data u16 moveEffect = gBattleMoves[move].effect; u8 effectiveness = AI_GetMoveEffectiveness(move); u8 atkPriority = GetMovePriority(battlerAtk, move); // targeting partner, check benefits of doing that instead - if (IsValidDoubleBattle(battlerAtk) && targetSameSide) - return AI_CheckPartner(battlerAtk, battlerAtkPartner, move, score); + if (IsValidDoubleBattle(battlerAtk) && AI_DATA->targetSameSide) + return AI_CheckPartner(battlerAtk, AI_DATA->battlerAtkPartner, move, score); // check move results if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) @@ -4426,7 +4399,7 @@ static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SLEEP: case EFFECT_YAWN: - if (AI_CanPutToSleep(battlerAtk, battlerDef, defAbility, move, partnerMove)) + if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score++; if ((HasMoveEffect(battlerAtk, EFFECT_DREAM_EATER) || HasMoveEffect(battlerAtk, EFFECT_NIGHTMARE)) && !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) @@ -4455,35 +4428,81 @@ static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_ATTACK_UP: case EFFECT_ATTACK_UP_2: - //AI_CV_AttackUp + if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && GetHealthPercentage(battlerAtk) > 40 && AI_DATA->atkAbility != ABILITY_CONTRARY) + { + if (gBattleMons[battlerAtk].statStages[STAT_ATK] < 8) + score += 2; + else if (gBattleMons[battlerAtk].statStages[STAT_ATK] < 11) + score++; + } break; case EFFECT_DEFENSE_UP: case EFFECT_DEFENSE_UP_2: - //AI_CV_DefenseUp + if ((HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL) || IS_MOVE_PHYSICAL(gLastMoves[battlerDef])) && GetHealthPercentage(battlerAtk) > 70 && AI_DATA->atkAbility != ABILITY_CONTRARY) + { + if (gBattleMons[battlerAtk].statStages[STAT_DEF] < 8) + score += 2; // seems better to raise def at higher HP + else if (gBattleMons[battlerAtk].statStages[STAT_DEF] < 10) + score++; + } break; case EFFECT_SPEED_UP: case EFFECT_SPEED_UP_2: - //AI_CV_SpeedUp + if (IsBattlerFaster(AI_CHECK_SLOWER) && AI_DATA->atkAbility != ABILITY_CONTRARY) + score += 3; break; case EFFECT_SPECIAL_ATTACK_UP: case EFFECT_SPECIAL_ATTACK_UP_2: - //AI_CV_SpAtkUp + if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && GetHealthPercentage(battlerAtk) > 40 && AI_DATA->atkAbility != ABILITY_CONTRARY) + { + if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < 8) + score += 2; + else if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < 11) + score++; + } break; case EFFECT_SPECIAL_DEFENSE_UP: case EFFECT_SPECIAL_DEFENSE_UP_2: - //AI_CV_SpDefUp + if ((HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) || IS_MOVE_SPECIAL(gLastMoves[battlerDef])) && GetHealthPercentage(battlerAtk) > 70 && AI_DATA->atkAbility != ABILITY_CONTRARY) + { + if (gBattleMons[battlerAtk].statStages[STAT_SPDEF] < 8) + score += 2; // seems better to raise spdef at higher HP + else if (gBattleMons[battlerAtk].statStages[STAT_SPDEF] < 10) + score++; + } break; case EFFECT_ACCURACY_UP: case EFFECT_ACCURACY_UP_2: - //AI_CV_AccuracyUp + if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move)) + score += 3; // has moves with less than 80% accuracy + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move)) + score += 2; break; case EFFECT_EVASION_UP: case EFFECT_EVASION_UP_2: - //AI_CV_EvasionUp + case EFFECT_MINIMIZE: + if (AI_DATA->atkAbility != ABILITY_CONTRARY && !BattlerWillFaintFromWeather(battlerAtk, AI_DATA->atkAbility)) + { + if (!BattlerHasSecondaryDamage(battlerAtk) && !(gStatuses3[battlerAtk] & STATUS3_ROOTED)) + score += 3; + else + score += 2; + } break; + case EFFECT_ACUPRESSURE: + break; + + case EFFECT_ATTACK_ACCURACY_UP: // hone claws + break; + + case EFFECT_GROWTH: + case EFFECT_ATTACK_SPATK_UP: // work up + break; + case EFFECT_ATTACK_DOWN: case EFFECT_ATTACK_DOWN_2: - //AI_CV_AttackDown + if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + score += 2; break; case EFFECT_DEFENSE_DOWN: case EFFECT_DEFENSE_DOWN_2: @@ -4629,9 +4648,6 @@ static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_MEAN_LOOK: //AI_CV_Trap break; - case EFFECT_MINIMIZE: - //AI_CV_EvasionUp - break; case EFFECT_CURSE: //AI_CV_Curse break; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 324a312378..fa8f38ea29 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -267,6 +267,32 @@ bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch) } // move checks +// 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 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split) +{ + s32 i, moveType; + u32 usable = 0; + u32 unusable = CheckMoveLimitations(attacker, 0, 0xFF); + u16 *moves = GetMovesArray(attacker); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE + && moves[i] != 0xFFFF + && GetBattleMoveSplit(moves[i]) == split + && !(unusable & gBitTable[i])) + { + SetTypeBeforeUsingMove(moves[i], attacker); + GET_MOVE_TYPE(moves[i], moveType); + if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, FALSE) != 0) + usable |= gBitTable[i]; + } + } + + return (usable == 0); +} + static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef) { bool32 isCrit; @@ -1022,6 +1048,21 @@ bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability) return TRUE; } +bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +{ + if (IsBattlerFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex)) + return FALSE; //Don't bother lowering stats if can kill enemy. + + if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4 && HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + && defAbility != ABILITY_WHITE_SMOKE + //&& defAbility != ABILITY_FULLMETALBODY + && defAbility != ABILITY_HYPER_CUTTER) + return TRUE; + return FALSE; +} + bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index) { s32 dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][index]; @@ -1081,6 +1122,33 @@ bool32 HasMoveEffect(u32 battlerId, u16 moveEffect) return FALSE; } +bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 ignoreStatus, u16 atkAbility, u16 defAbility, u16 atkHoldEffect, u16 defHoldEffect, u16 move) +{ + s32 i; + u16 *moves = GetMovesArray(battlerAtk); + u8 moveLimitations = CheckMoveLimitations(battlerAtk, 0, 0xFF); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] == MOVE_NONE || moves[i] == 0xFFFF) + continue; + + if (!(gBitTable[i] & moveLimitations)) + { + if (ignoreStatus && IS_MOVE_STATUS(moves[i])) + continue; + else if ((!IS_MOVE_STATUS(moves[i]) && gBattleMoves[move].accuracy == 0) + || gBattleMoves[move].target & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) + continue; + + if (AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, move) <= accCheck) + return TRUE; + } + } + + return FALSE; +} + bool32 IsInstructBannedMove(u16 move) { u32 i; From 31ec3e84799719edc4c492601f7a10d647876b5f Mon Sep 17 00:00:00 2001 From: Evan Date: Sat, 19 Dec 2020 21:58:23 -0700 Subject: [PATCH 07/36] non-partner good move checks --- data/battle_ai_scripts.s | 62 - include/battle.h | 6 + include/battle_ai_switch_items.h | 1 + include/battle_ai_util.h | 66 +- include/constants/battle.h | 3 +- include/constants/battle_ai.h | 2 + include/item.h | 1 + src/battle_ai_script_commands.c | 2195 ++++++++++++++++++++++-------- src/battle_ai_switch_items.c | 2 +- src/battle_ai_util.c | 1575 ++++++++++++++++++++- src/item.c | 23 + 11 files changed, 3258 insertions(+), 678 deletions(-) diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index c71c6b3c1b..0ea7573740 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -2301,68 +2301,6 @@ AI_CV_Encore_End: end AI_CV_Encore_EncouragedMovesToEncore: - .byte EFFECT_DREAM_EATER - .byte EFFECT_ATTACK_UP - .byte EFFECT_DEFENSE_UP - .byte EFFECT_SPEED_UP - .byte EFFECT_SPECIAL_ATTACK_UP - .byte EFFECT_HAZE - .byte EFFECT_ROAR - .byte EFFECT_CONVERSION - .byte EFFECT_TOXIC - .byte EFFECT_LIGHT_SCREEN - .byte EFFECT_REST - .byte EFFECT_SUPER_FANG - .byte EFFECT_SPECIAL_DEFENSE_UP_2 - .byte EFFECT_CONFUSE - .byte EFFECT_POISON - .byte EFFECT_PARALYZE - .byte EFFECT_LEECH_SEED - .byte EFFECT_DO_NOTHING - .byte EFFECT_ATTACK_UP_2 - .byte EFFECT_ENCORE - .byte EFFECT_CONVERSION_2 - .byte EFFECT_LOCK_ON - .byte EFFECT_HEAL_BELL - .byte EFFECT_MEAN_LOOK - .byte EFFECT_NIGHTMARE - .byte EFFECT_PROTECT - .byte EFFECT_SKILL_SWAP - .byte EFFECT_FORESIGHT - .byte EFFECT_PERISH_SONG - .byte EFFECT_SANDSTORM - .byte EFFECT_ENDURE - .byte EFFECT_SWAGGER - .byte EFFECT_ATTRACT - .byte EFFECT_SAFEGUARD - .byte EFFECT_RAIN_DANCE - .byte EFFECT_SUNNY_DAY - .byte EFFECT_BELLY_DRUM - .byte EFFECT_PSYCH_UP - .byte EFFECT_FUTURE_SIGHT - .byte EFFECT_FAKE_OUT - .byte EFFECT_STOCKPILE - .byte EFFECT_SPIT_UP - .byte EFFECT_SWALLOW - .byte EFFECT_HAIL - .byte EFFECT_TORMENT - .byte EFFECT_WILL_O_WISP - .byte EFFECT_FOLLOW_ME - .byte EFFECT_CHARGE - .byte EFFECT_TRICK - .byte EFFECT_ROLE_PLAY - .byte EFFECT_INGRAIN - .byte EFFECT_RECYCLE - .byte EFFECT_KNOCK_OFF - .byte EFFECT_SKILL_SWAP - .byte EFFECT_IMPRISON - .byte EFFECT_REFRESH - .byte EFFECT_GRUDGE - .byte EFFECT_TEETER_DANCE - .byte EFFECT_MUD_SPORT - .byte EFFECT_WATER_SPORT - .byte EFFECT_DRAGON_DANCE - .byte EFFECT_CAMOUFLAGE .byte -1 AI_CV_PainSplit: diff --git a/include/battle.h b/include/battle.h index 07b8289725..12fe42f8f1 100644 --- a/include/battle.h +++ b/include/battle.h @@ -239,20 +239,26 @@ struct AiLogicData { //attacker data u16 atkAbility; + u16 atkItem; u16 atkHoldEffect; u8 atkParam; + u16 atkSpecies; // target data u16 defAbility; + u16 defItem; u16 defHoldEffect; u8 defParam; + u16 defSpecies; // attacker partner data u8 battlerAtkPartner; u16 partnerMove; u16 atkPartnerAbility; + u16 atkPartnerHoldEffect; bool32 targetSameSide; // target partner data u8 battlerDefPartner; u16 defPartnerAbility; + u16 defPartnerHoldEffect; }; struct AI_ThinkingStruct diff --git a/include/battle_ai_switch_items.h b/include/battle_ai_switch_items.h index 9780fae705..1411384508 100644 --- a/include/battle_ai_switch_items.h +++ b/include/battle_ai_switch_items.h @@ -14,5 +14,6 @@ enum void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId); void AI_TrySwitchOrUseItem(void); u8 GetMostSuitableMonToSwitchInto(void); +bool32 ShouldSwitch(void); #endif // GUARD_BATTLE_AI_SWITCH_ITEMS_H diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 043235fa80..7fd991bf2c 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -1,7 +1,7 @@ #ifndef GUARD_BATTLE_AI_UTIL_H #define GUARD_BATTLE_AI_UTIL_H -// for IsBattlerFaster +// for IsAiFaster #define AI_CHECK_FASTER 0 // if_user_faster #define AI_CHECK_SLOWER 1 // if_target_faster @@ -20,25 +20,36 @@ void SaveBattlerData(u8 battlerId); void SetBattlerData(u8 battlerId); void RestoreBattlerData(u8 battlerId); +bool32 AtMaxHp(u8 battler); u32 GetHealthPercentage(u8 battler); bool32 IsBattlerTrapped(u8 battler, bool8 switching); -bool32 IsBattlerFaster(u8 battler); +bool32 IsAiFaster(u8 battler); bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk); +bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits); bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod); s32 AI_GetAbility(u32 battlerId); u16 AI_GetHoldEffect(u32 battlerId); u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move); bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move); bool32 AI_WeatherHasEffect(void); -bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index); +bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits); bool32 AI_IsBattlerGrounded(u8 battlerId); -bool32 BattlerHasDamagingMove(u8 battlerId); -bool32 BattlerHasSecondaryDamage(u8 battlerId); +bool32 HasDamagingMove(u8 battlerId); +bool32 HasDamagingMoveOfType(u8 battlerId, u8 type); +u32 GetBattlerSecondaryDamage(u8 battlerId); bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability); +bool32 BattlerWillFaintFromSecondaryDamage(u8 battler, u16 ability); bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move); bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex); u16 GetBattlerSideSpeedAverage(u8 battler); -bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage); +bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage); +bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent); +bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect); +bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 moveIndex); +bool32 IsRecycleEncouragedItem(u16 item); +bool32 CanKnockOffItem(u8 battler, u16 item); +bool32 IsAbilityOfRating(u16 ability, s8 rating); +s8 GetAbilityRating(u16 ability); // stat stage checks bool32 AnyStatIsRaised(u8 battlerId); @@ -50,8 +61,15 @@ u32 CountPositiveStatStages(u8 battlerId); u32 CountNegativeStatStages(u8 battlerId); bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability); bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); +bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); +bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); +bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); +bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); +bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); +bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); // move checks +bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect); bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split); s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef); u8 GetMoveDamageResult(u16 move); @@ -59,10 +77,12 @@ u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); u8 AI_GetMoveEffectiveness(u16 move); u16 *GetMovesArray(u32 battler); bool32 IsConfusionMoveEffect(u16 moveEffect); +bool32 HasMove(u32 battlerId, u32 move); bool32 HasMoveWithSplit(u32 battler, u32 split); bool32 HasMoveWithType(u32 battler, u8 type); +bool32 HasMoveWithTypeAndSplit(u32 battler, u8 type, u8 split); bool32 HasMoveEffect(u32 battlerId, u16 moveEffect); -bool32 HasMoveWithLowAccuracy(u8, u8, u8, bool32, u16, u16, u16, u16, u16); +bool32 HasMoveWithLowAccuracy(u8, u8, u8, bool32, u16, u16, u16, u16); bool32 TestMoveFlagsInMoveset(u8 battler, u32 flags); bool32 IsAromaVeilProtectedMove(u16 move); bool32 IsNonVolatileStatusMoveEffect(u16 moveEffect); @@ -73,15 +93,36 @@ bool32 IsHazardMoveEffect(u16 moveEffect); bool32 MoveCallsOtherMove(u16 move); bool32 MoveRequiresRecharging(u16 move); bool32 IsInstructBannedMove(u16 move); +bool32 IsEncoreEncouragedEffect(u16 moveEffect); +void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s16 *score); +bool32 ShouldSetSandstorm(u8 battler, u16 ability, u16 holdEffect); +bool32 ShouldSetHail(u8 battler, u16 ability, u16 holdEffect); +bool32 ShouldSetRain(u8 battlerAtk, u16 ability, u16 holdEffect); +bool32 ShouldSetSun(u8 battlerAtk, u16 atkAbility, u16 holdEffect); +bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef); +bool32 IsHealingMoveEffect(u16 effect); +bool32 HasHealingEffect(u32 battler); +bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move); +bool32 IsThawingMove(u16 move); +bool32 HasThawingMove(u8 battlerId); // status checks +bool32 CanBeBurned(u8 battler, u16 ability); +bool32 CanBePoisoned(u8 battler, u16 ability); +bool32 IsBattlerIncapacitated(u8 battler, u16 ability); +bool32 CanSleep(u8 battler, u16 ability); bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); +bool32 ShouldPoisonSelf(u8 battler, u16 ability); bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); +bool32 ShouldBurnSelf(u8 battler, u16 ability); bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGender, u8 defGender); bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof); +u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move); +bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move); +bool32 IsWakeupTurn(u8 battler); // partner logic u16 GetAllyChosenMove(void); @@ -95,10 +136,21 @@ bool32 PartnerMoveEffectIsTerrain(u8 battlerAtkPartner, u16 partnerMove); bool32 PartnerMoveIs(u8 battlerAtkPartner, u16 partnerMove, u16 moveCheck); bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove); bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove); +bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move); // party logic s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon); s32 CountUsablePartyMons(u8 battlerId); bool32 IsPartyFullyHealedExceptBattler(u8 battler); +bool32 PartyHasMoveSplit(u8 battlerId, u8 split); +bool32 SideHasMoveSplit(u8 battlerId, u8 split); + +// score increases +void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score); +void IncreasePoisonScore(u8 battlerAtk, u8 battlerdef, u16 move, s16 *score); +void IncreaseBurnScore(u8 battlerAtk, u8 battlerdef, u16 move, s16 *score); +void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); +void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); +void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); #endif //GUARD_BATTLE_AI_UTIL_H \ No newline at end of file diff --git a/include/constants/battle.h b/include/constants/battle.h index 0bc06b0adb..d836117eaa 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -220,7 +220,8 @@ #define SIDE_STATUS_CRAFTY_SHIELD (1 << 20) #define SIDE_STATUS_MAT_BLOCK (1 << 21) -#define SIDE_HAZARDS_ANY (SIDE_STATUS_SPIKES | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_STEALTH_ROCK) +#define SIDE_STATUS_HAZARDS_ANY (SIDE_STATUS_SPIKES | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_STEALTH_ROCK) +#define SIDE_STATUS_SCREEEN_ANY (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL) // Field affecting statuses. #define STATUS_FIELD_MAGIC_ROOM 0x1 diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 5e97ab6aa9..3dac82bc43 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -50,6 +50,8 @@ #define AI_FLAG_HELP_PARTNER (1 << 10) // AI can try to help partner. If not set, will tend not to target partner #define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc #define AI_FLAG_PREFER_STATUS_MOVES (1 << 12) // 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 << 13) // AI stalls battle and prefers secondary damage/trapping/etc. TODO not finished +#define AI_FLAG_SCREENER (1 << 14) // AI prefers screening effects like reflect, mist, etc. TODO unfinished // 'other' ai logic flags #define AI_FLAG_ROAMING (1 << 29) diff --git a/include/item.h b/include/item.h index 87ff57bc79..90a9c2577a 100644 --- a/include/item.h +++ b/include/item.h @@ -74,5 +74,6 @@ ItemUseFunc ItemId_GetFieldFunc(u16 itemId); u8 ItemId_GetBattleUsage(u16 itemId); ItemUseFunc ItemId_GetBattleFunc(u16 itemId); u8 ItemId_GetSecondaryId(u16 itemId); +bool32 IsPinchBerryItemEffect(u16 holdEffect); #endif // GUARD_ITEM_H diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 2b666a16b9..0c1382a51f 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -17,6 +17,7 @@ #include "constants/battle_move_effects.h" #include "constants/hold_effects.h" #include "constants/moves.h" +#include "constants/items.h" #define AI_ACTION_DONE 0x0001 #define AI_ACTION_FLEE 0x0002 @@ -182,20 +183,20 @@ EWRAM_DATA u8 sBattler_AI = 0; // const rom data typedef void (*BattleAICmdFunc)(void); -static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static u8 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = +static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = { [0] = AI_CheckBadMove, // AI_FLAG_CHECK_BAD_MOVE [1] = AI_TryToFaint, // AI_FLAG_TRY_TO_FAINT @@ -507,20 +508,26 @@ static void GetAiLogicData(u8 battlerAtk, u8 battlerDef) { // attacker data AI_DATA->atkAbility = AI_GetAbility(battlerAtk); + AI_DATA->atkItem = gBattleMons[battlerAtk].item; AI_DATA->atkHoldEffect = AI_GetHoldEffect(battlerAtk); AI_DATA->atkParam = GetBattlerHoldEffectParam(battlerAtk); + AI_DATA->atkSpecies = gBattleMons[battlerAtk].species; // target data AI_DATA->defAbility = AI_GetAbility(battlerDef); + AI_DATA->defItem = (AI_GetHoldEffect(battlerDef) == HOLD_EFFECT_NONE) ? ITEM_NONE : gBattleMons[battlerDef].item; AI_DATA->defHoldEffect = AI_GetHoldEffect(battlerDef); AI_DATA->defParam = GetBattlerHoldEffectParam(battlerDef); + AI_DATA->defSpecies = gBattleMons[battlerDef].species; // attacker partner data AI_DATA->battlerAtkPartner = BATTLE_PARTNER(battlerAtk); AI_DATA->partnerMove = GetAllyChosenMove(); AI_DATA->atkPartnerAbility = AI_GetAbility(AI_DATA->battlerAtkPartner); + AI_DATA->atkPartnerHoldEffect = AI_GetHoldEffect(AI_DATA->battlerAtkPartner); AI_DATA->targetSameSide = IsTargetingPartner(battlerAtk, battlerDef); // target partner data AI_DATA->battlerDefPartner = BATTLE_PARTNER(battlerDef); AI_DATA->defPartnerAbility = AI_GetAbility(AI_DATA->battlerDefPartner); + AI_DATA->defPartnerHoldEffect = AI_GetHoldEffect(AI_DATA->battlerDefPartner); } static u8 ChooseMoveOrAction_Singles(void) @@ -557,7 +564,7 @@ static u8 ChooseMoveOrAction_Singles(void) gActiveBattler = sBattler_AI; // If can switch. - if (CountUsablePartyMons(sBattler_AI) >= 1 + if (CountUsablePartyMons(sBattler_AI) > 0 && !IsAbilityPreventingEscape(sBattler_AI) && !(gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) && !(gStatuses3[gActiveBattler] & STATUS3_ROOTED) @@ -1163,7 +1170,7 @@ static void Cmd_if_user_has_attacking_move(void) static void Cmd_if_user_has_no_attacking_moves(void) { - //BattlerHasDamagingMove + //HasDamagingMove } static void Cmd_get_turn_count(void) @@ -1246,7 +1253,7 @@ static void Cmd_if_not_equal_u32(void) static void Cmd_if_user_goes(void) { - // IsBattlerFaster + // IsAiFaster } static void Cmd_nullsub_2A(void) @@ -2292,27 +2299,9 @@ static void Cmd_compare_speeds(void) gAIScriptPtr += 3; } -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]; -} - static void Cmd_is_wakeup_turn(void) { - u32 battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - // Check if rest was used 2 turns ago - if ((gBattleMons[battler].status1 & STATUS1_SLEEP) == 1 && FindMoveUsedXTurnsAgo(battler, 2) == MOVE_REST) - AI_THINKING_STRUCT->funcResult = TRUE; - else - AI_THINKING_STRUCT->funcResult = FALSE; - - gAIScriptPtr += 2; + //IsWakeupTurn } static void Cmd_if_has_move_with_accuracy_lt(void) @@ -2341,7 +2330,7 @@ static void Cmd_if_has_move_with_accuracy_lt(void) // AI Functions -static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // move data u8 atkPriority = GetMovePriority(battlerAtk, move); @@ -2350,6 +2339,9 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u8 moveTarget = gBattleMoves[move].target; u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); u8 effectiveness = AI_GetMoveEffectiveness(move); + bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); + u32 i; + u16 predictedMove = gLastMoves[battlerDef]; // TODO better move prediction if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HELP_PARTNER) && AI_DATA->targetSameSide) return score; // don't consider ally presence @@ -2360,9 +2352,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // check powder moves if (TestMoveFlags(move, FLAG_POWDER)) { - if ((B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS)) - || AI_DATA->defAbility == ABILITY_OVERCOAT - || GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_SAFETY_GOOGLES) + if (!IsAffectedByPowder(battlerDef, AI_DATA->defAbility, AI_DATA->defHoldEffect)) score -= 10; } @@ -2499,7 +2489,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // def ability checks // target partner ability checks - if (IsValidDoubleBattle(battlerAtk) && !IsTargetingPartner(battlerAtk, battlerDef)) + if (isDoubleBattle && !IsTargetingPartner(battlerAtk, battlerDef)) { switch (AI_DATA->defPartnerAbility) { @@ -2599,15 +2589,15 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { score -= 10; } - else if (CountUsablePartyMons(battlerDef) == 1 && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex)) + else if (CountUsablePartyMons(battlerDef) == 0 && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) { ; // target has 1 pkmn left but you can faint it -> good to use } - else if (IsValidDoubleBattle(battlerAtk)) + else if (isDoubleBattle) { - if (CountUsablePartyMons(battlerDef) == 2 - && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) - && CanAttackerFaintTarget(AI_DATA->battlerAtkPartner, BATTLE_PARTNER(battlerDef), *(gBattleStruct->chosenMovePositions + AI_DATA->battlerAtkPartner))) + if (CountUsablePartyMons(battlerDef) != 0 + && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0) + && CanAttackerFaintTarget(AI_DATA->battlerAtkPartner, BATTLE_PARTNER(battlerDef), *(gBattleStruct->chosenMovePositions + AI_DATA->battlerAtkPartner), 0)) { ; // good } @@ -2618,9 +2608,9 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex)) + if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) { - if (CountUsablePartyMons(battlerDef) == 1) + if (CountUsablePartyMons(battlerDef) == 0) { ; //Good to use move } @@ -2641,20 +2631,17 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_COPYCAT: - //TODO - predict def move - break; case EFFECT_MIRROR_MOVE: - //TODO - predict def move - break; + return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); case EFFECT_TELEPORT: if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { - if (CountUsablePartyMons(battlerAtk) == 1) + if (CountUsablePartyMons(battlerAtk) == 0) score -= 10; } else if (GetBattlerSide(battlerAtk) == B_SIDE_OPPONENT) { - if (IsValidDoubleBattle(battlerAtk) || IsBattlerTrapped(battlerAtk, FALSE)) + if (isDoubleBattle || IsBattlerTrapped(battlerAtk, FALSE)) score -= 10; } break; @@ -2701,7 +2688,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_FLOWER_SHIELD: if (!IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) - && !(IsValidDoubleBattle(battlerAtk) && IS_BATTLER_OF_TYPE(AI_DATA->battlerAtkPartner, TYPE_GRASS))) + && !(isDoubleBattle && IS_BATTLER_OF_TYPE(AI_DATA->battlerAtkPartner, TYPE_GRASS))) score -= 10; break; case EFFECT_MAGNETIC_FLUX: @@ -2711,12 +2698,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) score -= 10; } - else if (!IsValidDoubleBattle(battlerAtk)) + else if (!isDoubleBattle) { score -= 10; // our stats wont rise from this move } - if (IsValidDoubleBattle(battlerAtk)) + if (isDoubleBattle) { if (AI_DATA->atkPartnerAbility == ABILITY_PLUS || AI_DATA->atkPartnerAbility == ABILITY_MINUS) { @@ -2731,7 +2718,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_AROMATIC_MIST: - if (!IsValidDoubleBattle(battlerAtk) || gBattleMons[AI_DATA->battlerAtkPartner].hp == 0 || !BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPDEF)) + if (!isDoubleBattle || gBattleMons[AI_DATA->battlerAtkPartner].hp == 0 || !BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPDEF)) score -= 10; break; case EFFECT_SPEED_UP: @@ -2752,7 +2739,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_ROTOTILLER: - if (IsValidDoubleBattle(battlerAtk)) + if (isDoubleBattle) { if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) && AI_IsBattlerGrounded(battlerAtk) @@ -2781,12 +2768,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!BattlerShouldRaiseAttacks(battlerAtk, AI_DATA->atkAbility)) score -= 10; } - else if (!IsValidDoubleBattle(battlerAtk)) + else if (!isDoubleBattle) { score -= 10; // no partner and our stats wont rise, so don't use } - if (IsValidDoubleBattle(battlerAtk)) + if (isDoubleBattle) { if (AI_DATA->atkPartnerAbility == ABILITY_PLUS || AI_DATA->atkPartnerAbility == ABILITY_MINUS) { @@ -2904,7 +2891,6 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - u32 i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) @@ -2918,7 +2904,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_BIDE: - if (!BattlerHasDamagingMove(battlerDef) + if (!HasDamagingMove(battlerDef) || GetHealthPercentage(battlerAtk) < 30 //Close to death || gBattleMons[battlerDef].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) //No point in biding if can't take damage score -= 10; @@ -2928,12 +2914,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; // don't scare away pokemon twice //Don't blow out a Pokemon that'll faint soon or is taking a a lot of secondary damage - if (GetHealthPercentage(battlerDef) < 10 && BattlerHasSecondaryDamage(battlerDef)) + if (GetHealthPercentage(battlerDef) < 10 && GetBattlerSecondaryDamage(battlerDef)) score -= 10; else if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) score -= 10; - if (CountUsablePartyMons(battlerDef) == 1 + if (CountUsablePartyMons(battlerDef) == 0 || AI_DATA->defAbility == ABILITY_SUCTION_CUPS || gStatuses3[battlerDef] & STATUS3_ROOTED) score -= 10; @@ -2941,7 +2927,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_HIT_SWITCH_TARGET: if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; // don't scare away pokemon twice - else if (GetHealthPercentage(battlerDef) < 10 && BattlerHasSecondaryDamage(battlerDef)) + else if (GetHealthPercentage(battlerDef) < 10 && GetBattlerSecondaryDamage(battlerDef)) score -= 10; // don't blow away mon that will faint soon else if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) score -= 10; @@ -2951,10 +2937,24 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IS_BATTLER_OF_TYPE(battlerAtk, gBattleMoves[gBattleMons[battlerAtk].moves[0]].type)) score -= 10; break; - case EFFECT_RESTORE_HP: case EFFECT_REST: + if (!CanSleep(battlerAtk, AI_DATA->atkAbility)) + score -= 10; + //fallthrough + case EFFECT_RESTORE_HP: + case EFFECT_SOFTBOILED: + case EFFECT_ROOST: + if (AtMaxHp(battlerAtk)) + score -= 10; + else if (GetHealthPercentage(battlerAtk) >= 90) + score -= 9; //No point in healing, but should at least do it if nothing better + break; case EFFECT_MORNING_SUN: - if (GetHealthPercentage(battlerAtk) == 100) + case EFFECT_SYNTHESIS: + case EFFECT_MOONLIGHT: + if (AI_WeatherHasEffect() && (gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_SANDSTORM_ANY | WEATHER_HAIL_ANY))) + score -= 3; + else if (AtMaxHp(battlerAtk)) score -= 10; else if (GetHealthPercentage(battlerAtk) >= 90) score -= 9; //No point in healing, but should at least do it if nothing better @@ -2964,7 +2964,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; else if (battlerDef == AI_DATA->battlerAtkPartner) break; //Always heal your ally - else if (GetHealthPercentage(battlerAtk) == 100) + else if (AtMaxHp(battlerAtk)) score -= 10; else if (GetHealthPercentage(battlerAtk) >= 90) score -= 8; //No point in healing, but should at least do it if nothing better @@ -3008,6 +3008,10 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!ShouldTryOHKO(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, accuracy, move)) score -= 10; break; + case EFFECT_SUPER_FANG: + if (GetHealthPercentage(battlerDef) < 50) + score -= 4; + break; case EFFECT_RECOIL_IF_MISS: if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && accuracy < 75) score -= 6; @@ -3074,7 +3078,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_PARALYZE: if (move != MOVE_GLARE && gMoveResultFlags & MOVE_RESULT_NO_EFFECT) score -= 10; - else if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + else if (!AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_TWO_TURNS_ATTACK: @@ -3091,7 +3095,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_RECHARGE: if (AI_DATA->atkAbility != ABILITY_TRUANT - && !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex)) + && !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) score -= 2; break; case EFFECT_SPITE: @@ -3102,7 +3106,11 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || gLastMoves[battlerDef] == 0xFFFF) score -= 10; } - // TODO - if no predicted move, decrease viability + else if (predictedMove == MOVE_NONE) + { + // TODO predicted move separate from gLastMoves + score -= 10; + } break; case EFFECT_METRONOME: break; @@ -3123,7 +3131,10 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) score -= 10; } - //TODO - if predictive move = MOVE_NONE, score -= 10 + else if (predictedMove == MOVE_NONE) + { + score -= 10; + } } else { @@ -3132,11 +3143,11 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_COUNTER: case EFFECT_MIRROR_COAT: - //TODO - predicted move - /*if (GetBattleMoveSplit(predictedMove) == SPLIT_STATUS - || predictedMove == MOVE_NONE - || DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, predictedMove) - score -= 10;*/ + if (IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) + score--; + if (predictedMove == MOVE_NONE || GetBattleMoveSplit(predictedMove) == SPLIT_STATUS + || DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, predictedMove)) + score -= 10; break; case EFFECT_ENCORE: if (gDisableStructs[battlerDef].encoreTimer == 0 @@ -3149,9 +3160,10 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || gLastMoves[battlerDef] == 0xFFFF) score -= 10; } - //TODO predicted moves - //else if (predictedMove == MOVE_NONE) - //score -= 10; + else if (predictedMove == MOVE_NONE) + { + score -= 10; + } } else { @@ -3165,11 +3177,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SNORE: case EFFECT_SLEEP_TALK: - // AI shouldn't really know if its about to wake up since its random - /*if (((gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) == 1 || !(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP)) - && AI_DATA->atkAbility != ABILITY_COMATOSE) - score -= 10;*/ - if (!(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) && AI_DATA->atkAbility != ABILITY_COMATOSE) + if (IsWakeupTurn(battlerAtk) || (!(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) && AI_DATA->atkAbility != ABILITY_COMATOSE)) score -= 10; break; case EFFECT_CONVERSION_2: @@ -3234,7 +3242,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_ENDURE: - if (gBattleMons[battlerAtk].hp == 1 || BattlerHasSecondaryDamage(battlerAtk)) //Don't use Endure if you'll die after using it + if (gBattleMons[battlerAtk].hp == 1 || GetBattlerSecondaryDamage(battlerAtk)) //Don't use Endure if you'll die after using it score -= 10; break; case EFFECT_PROTECT: @@ -3245,7 +3253,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case MOVE_QUICK_GUARD: case MOVE_WIDE_GUARD: case MOVE_CRAFTY_SHIELD: - if (!IsValidDoubleBattle(battlerAtk)) + if (!isDoubleBattle) { score -= 10; decreased = TRUE; @@ -3273,7 +3281,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && move != MOVE_WIDE_GUARD && move != MOVE_CRAFTY_SHIELD) //These moves have infinite usage { - if (BattlerHasSecondaryDamage(battlerAtk) + if (GetBattlerSecondaryDamage(battlerAtk) && AI_DATA->defAbility != ABILITY_MOXIE && AI_DATA->defAbility != ABILITY_BEAST_BOOST) { @@ -3281,7 +3289,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (gDisableStructs[battlerAtk].protectUses == 1 && Random() % 100 < 50) { - if (!IsValidDoubleBattle(battlerAtk)) + if (!isDoubleBattle) score -= 6; else score -= 10; //Don't try double protecting in doubles @@ -3349,12 +3357,12 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 9; break; case EFFECT_PERISH_SONG: - if (IsValidDoubleBattle(battlerAtk)) + if (isDoubleBattle) { - if (CountUsablePartyMons(battlerAtk) <= 2 + if (CountUsablePartyMons(battlerAtk) == 0 && AI_DATA->atkAbility != ABILITY_SOUNDPROOF && AI_DATA->atkPartnerAbility != ABILITY_SOUNDPROOF - && CountUsablePartyMons(FOE(battlerAtk)) >= 3) + && CountUsablePartyMons(FOE(battlerAtk)) >= 1) { score -= 10; //Don't wipe your team if you're going to lose } @@ -3370,8 +3378,8 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (CountUsablePartyMons(battlerAtk) == 1 && AI_DATA->atkAbility != ABILITY_SOUNDPROOF - && CountUsablePartyMons(battlerDef) >= 2) + if (CountUsablePartyMons(battlerAtk) == 0 && AI_DATA->atkAbility != ABILITY_SOUNDPROOF + && CountUsablePartyMons(battlerDef) >= 1) score -= 10; if (gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG || AI_GetAbility(FOE(battlerAtk)) == ABILITY_SOUNDPROOF) @@ -3423,7 +3431,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_PARTING_SHOT: - if (CountUsablePartyMons(battlerAtk) == 1) + if (CountUsablePartyMons(battlerAtk) == 0) score -= 10; break; case EFFECT_BATON_PASS: @@ -3441,14 +3449,14 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; // check damage/accuracy //Spin checks - if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_HAZARDS_ANY)) + if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY)) score -= 6; 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_HAZARDS_ANY) + || gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY) { if (PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) { @@ -3457,13 +3465,13 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } } - if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_HAZARDS_ANY) + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_HAZARDS_ANY) { score -= 10; //Don't blow away opposing hazards break; } - if (IsValidDoubleBattle(battlerAtk)) + if (isDoubleBattle) { if (IsHazardMoveEffect(gBattleMoves[AI_DATA->partnerMove].effect) // partner is going to set up hazards && GetWhoStrikesFirst(AI_DATA->battlerAtkPartner, battlerAtk, FALSE)) // partner is going to set up before the potential Defog @@ -3486,7 +3494,6 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_PSYCH_UP: // haze stats check { - u32 i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) @@ -3513,11 +3520,10 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 4; break; case EFFECT_SEMI_INVULNERABLE: - //TODO - predicted moves - /*if (predictedMove != MOVE_NONE - && MoveWouldHitFirst(move, battlerAtk, battlerDef) + if (predictedMove != MOVE_NONE + && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 && gBattleMoves[predictedMove].effect == EFFECT_SEMI_INVULNERABLE) - score -= 10;*/ // Don't Fly if opponent is going to fly after you + score -= 10; // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you if (BattlerWillFaintFromWeather(battlerAtk, AI_DATA->atkAbility) && (move == MOVE_FLY || move == MOVE_BOUNCE)) @@ -3532,9 +3538,9 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) else if (move == MOVE_FAKE_OUT) { if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || AI_DATA->atkAbility == ABILITY_GORILLA_TACTICS) - && (CountUsablePartyMons(battlerDef) >= 2 || !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex))) + && (CountUsablePartyMons(battlerDef) > 0 || !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))) { - if (CountUsablePartyMons(battlerAtk) == 1) + if (CountUsablePartyMons(battlerAtk) == 0) score -= 10; // Don't lock the attacker into Fake Out if they can't switch out afterwards. } } @@ -3556,7 +3562,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (GetHealthPercentage(battlerAtk) == 100) + if (AtMaxHp(battlerAtk)) score -= 10; else if (GetHealthPercentage(battlerAtk) >= 80) score -= 5; // do it if nothing better @@ -3584,32 +3590,28 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_MEMENTO: - if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; else if (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE && gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE) score -= 10; break; case EFFECT_HEALING_WISH: //healing wish, lunar dance - if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; else if (IsPartyFullyHealedExceptBattler(battlerAtk)) score -= 10; break; case EFFECT_FINAL_GAMBIT: - if (CountUsablePartyMons(battlerAtk) == 1 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_FOCUS_PUNCH: - //TODO predicted moves - /*if (predictedMove != MOVE_NONE - && !DoesSubstituteBlockMove(battlerAtk, battlerDef, predictedMove) - && SPLIT(predictedMove) != SPLIT_STATUS + if (predictedMove != MOVE_NONE + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + && !IS_MOVE_STATUS(predictedMove) && gBattleMoves[predictedMove].power != 0) - score -= 10;*/ //Probably better not to use it + score -= 10; // Probably better not to use it break; - //TODO - // case EFFECT_SHELL_TRAP: - // case EFFECT_BEAK_BLAST: case EFFECT_NATURE_POWER: return AI_CheckBadMove(battlerAtk, battlerDef, GetNaturePowerMove(), score); case EFFECT_CHARGE: @@ -3631,7 +3633,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_FOLLOW_ME: case EFFECT_HELPING_HAND: - if (!IsValidDoubleBattle(battlerAtk) + if (!isDoubleBattle || !IsBattlerAlive(AI_DATA->battlerAtkPartner) || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) || (AI_DATA->partnerMove != MOVE_NONE && IS_MOVE_STATUS(AI_DATA->partnerMove)) @@ -3658,13 +3660,15 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || IsRolePlayBannedAbilityAtk(AI_DATA->atkAbility) || IsRolePlayBannedAbility(AI_DATA->defAbility)) score -= 10; + else if (IsAbilityOfRating(AI_DATA->atkAbility, 5)) + score -= 4; break; case EFFECT_WISH: if (gWishFutureKnock.wishCounter[battlerAtk] != 0) score -= 10; break; case EFFECT_ASSIST: - if (CountUsablePartyMons(battlerAtk) == 1) + if (CountUsablePartyMons(battlerAtk) == 0) score -= 10; // no teammates to assist from break; case EFFECT_INGRAIN: @@ -3680,6 +3684,8 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (move == MOVE_HYPERSPACE_FURY && gBattleMons[battlerAtk].species != SPECIES_HOOPA_UNBOUND) score -= 10; #endif + if (effectiveness <= AI_EFFECTIVENESS_x0_5) + score -= 2; // really don't waste the stat loss on a weak attack break; case EFFECT_MAGIC_COAT: if (!TestMoveFlagsInMoveset(battlerDef, FLAG_MAGICCOAT_AFFECTED)) @@ -3787,19 +3793,6 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) score -= 10; break; - // TODO - /*case EFFECT_NO_RETREAT: - if (TrappedByNoRetreat(battlerAtk)) - score -= 10; - break; - case EFFECT_EXTREME_EVOBOOST: - if (MainStatsMaxed(battlerAtk)) - score -= 10; - break; - case EFFECT_CLANGOROUS_SOUL: - if (gBattleMons[battlerAtk].hp <= gBattleMons[battlerAtk].maxHP / 3) - score -= 10; - break;*/ case EFFECT_BULK_UP: if (AI_DATA->atkAbility == ABILITY_CONTRARY) score -= 10; @@ -3940,16 +3933,17 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_ME_FIRST: - //TODO - predicted move - /*if (predictedMove != MOVE_NONE) + if (predictedMove != MOVE_NONE) { - if (!MoveWouldHitFirst(move, battlerAtk, battlerDef)) - score -= 10; + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) + score -= 10; // Target is predicted to go first, Me First will fail else - return AIScript_Negatives(battlerAtk, battlerDef, predictedMove, originalViability, data); + return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); + } + else + { + score -= 10; //Target is predicted to switch most likely } - else //Target is predicted to switch most likely - score -= 10;*/ break; case EFFECT_NATURAL_GIFT: if (AI_DATA->atkAbility == ABILITY_KLUTZ @@ -3974,7 +3968,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_PLEDGE: - if (IsValidDoubleBattle(battlerAtk) && gBattleMons[AI_DATA->battlerAtkPartner].hp > 0) + if (isDoubleBattle && gBattleMons[AI_DATA->battlerAtkPartner].hp > 0) { if (AI_DATA->partnerMove != MOVE_NONE && gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_PLEDGE @@ -4022,15 +4016,14 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; - //TODO - //case EFFECT_PLASMA_FISTS: - //break; case EFFECT_FLING: if (!CanFling(battlerAtk)) + { score -= 10; + } else { - /* TODO + /* TODO Fling u8 effect = gFlingTable[gBattleMons[battlerAtk].item].effect; switch (effect) { @@ -4108,7 +4101,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_HIT_ENEMY_HEAL_ALLY: // pollen puff if (AI_DATA->targetSameSide) { - if (GetHealthPercentage(battlerDef) == 100) + if (AtMaxHp(battlerDef)) score -= 10; else if (gBattleMons[battlerDef].hp > gBattleMons[battlerDef].maxHP / 2) score -= 5; @@ -4122,7 +4115,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (GetHealthPercentage(battlerDef) == 100) + if (AtMaxHp(battlerDef)) score -= 10; else if (gBattleMons[battlerDef].hp > gBattleMons[battlerDef].maxHP / 2) score -= 5; @@ -4159,7 +4152,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { u16 instructedMove; if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) - instructedMove = MOVE_NONE; //TODO instructedMove = predictedMove; + instructedMove = predictedMove; else instructedMove = gLastMoves[battlerDef]; @@ -4176,7 +4169,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { score -= 10; } - else if (IsValidDoubleBattle(battlerAtk)) + else if (isDoubleBattle) { if (!AI_DATA->targetSameSide) score -= 10; @@ -4197,29 +4190,24 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_QUASH: - if (!IsValidDoubleBattle(battlerAtk) + if (!isDoubleBattle || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_AFTER_YOU: if (!AI_DATA->targetSameSide - || !IsValidDoubleBattle(battlerAtk) + || !isDoubleBattle || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SUCKER_PUNCH: - /*TODO predicted move if (predictedMove != MOVE_NONE) { - if (IS_MOVE_STATUS(predictedMove) - || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 - { + if (IS_MOVE_STATUS(predictedMove) || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // opponent going first score -= 10; - break; - } - }*/ + } break; case EFFECT_TAILWIND: if (gSideTimers[GetBattlerSide(battlerAtk)].tailwindTimer != 0 @@ -4248,16 +4236,6 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!CanUseLastResort(battlerAtk)) score -= 10; break; - //TODO - /*case EFFECT_SKY_DROP: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING)) - score -= 10; - if (WillFaintFromWeather(battlerAtk) - || MoveBlockedBySubstitute(move, battlerAtk, battlerDef) - || GetSpeciesWeight(gBattleMons[battlerDef].species, AI_DATA->defAbility, AI_DATA->defHoldEffect, battlerDef, TRUE) >= 2000) //200.0 kg - score -= 10; - break; - */ case EFFECT_SYNCHRONOISE: //Check holding ring target or is of same type if (AI_DATA->defHoldEffect == HOLD_EFFECT_RING_TARGET @@ -4268,7 +4246,49 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) else score -= 10; break; - + case EFFECT_ERUPTION: + if (effectiveness <= AI_EFFECTIVENESS_x0_5) + score--; + if (GetHealthPercentage(battlerDef) < 50) + score--; + break; + case EFFECT_VITAL_THROW: + if (IsAiFaster(AI_CHECK_FASTER) && GetHealthPercentage(battlerAtk) < 40) + score--; // don't want to move last + break; + case EFFECT_FLAIL: + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 // opponent should go first + || GetHealthPercentage(battlerAtk) > 50) + 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)) + score -= 10; + if (WillFaintFromWeather(battlerAtk) + || MoveBlockedBySubstitute(move, battlerAtk, battlerDef) + || GetSpeciesWeight(gBattleMons[battlerDef].species, AI_DATA->defAbility, AI_DATA->defHoldEffect, battlerDef, TRUE) >= 2000) //200.0 kg + score -= 10; + break; + */ + /*case EFFECT_NO_RETREAT: + if (TrappedByNoRetreat(battlerAtk)) + score -= 10; + break; + case EFFECT_EXTREME_EVOBOOST: + if (MainStatsMaxed(battlerAtk)) + score -= 10; + break; + case EFFECT_CLANGOROUS_SOUL: + if (gBattleMons[battlerAtk].hp <= gBattleMons[battlerAtk].maxHP / 3) + score -= 10; + break;*/ } // move effect checks // substitute check @@ -4286,7 +4306,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // helping hand check - if (IsValidDoubleBattle(battlerAtk) && AI_DATA->partnerMove != MOVE_NONE + if (isDoubleBattle && AI_DATA->partnerMove != MOVE_NONE && gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_HELPING_HAND && IS_MOVE_STATUS(move)) score -= 10; //Don't use a status move if partner wants to help @@ -4294,7 +4314,7 @@ static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } -static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { s32 dmg; u8 result; @@ -4305,10 +4325,10 @@ static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power == 0) return score; // can't make anything faint with no power - if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) && gBattleMoves[move].effect != EFFECT_EXPLOSION) + if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0) && gBattleMoves[move].effect != EFFECT_EXPLOSION) { // AI_TryToFaint_Can - if (IsBattlerFaster(AI_CHECK_FASTER) || TestMoveFlags(move, FLAG_HIGH_CRIT)) + if (IsAiFaster(AI_CHECK_FASTER) || TestMoveFlags(move, FLAG_HIGH_CRIT)) score += 4; else score += 2; @@ -4327,7 +4347,7 @@ static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } //AI_TryToFaint_CheckIfDanger - if (!IsBattlerFaster(AI_CHECK_FASTER) && CanTargetFaintAi(battlerDef, battlerAtk)) + if (!IsAiFaster(AI_CHECK_FASTER) && CanTargetFaintAi(battlerDef, battlerAtk)) { // AI_TryToFaint_Danger if (GetMoveDamageResult(move) != MOVE_POWER_BEST) score--; @@ -4338,21 +4358,24 @@ static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } -static u8 AI_CheckPartner(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_CheckPartner(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { //TODO return score; } -static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // move data u16 moveEffect = gBattleMoves[move].effect; u8 effectiveness = AI_GetMoveEffectiveness(move); u8 atkPriority = GetMovePriority(battlerAtk, move); + u16 predictedMove = gLastMoves[battlerDef]; //for now + bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); + u32 i; // targeting partner, check benefits of doing that instead - if (IsValidDoubleBattle(battlerAtk) && AI_DATA->targetSameSide) + if (isDoubleBattle && AI_DATA->targetSameSide) return AI_CheckPartner(battlerAtk, AI_DATA->battlerAtkPartner, move, score); // check move results @@ -4362,29 +4385,23 @@ static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // if target goes first and can kill us, lets try to use a priority move to at least do something if ((gBattleMons[battlerDef].status2 & (STATUS2_RECHARGE | STATUS2_BIDE)) && CanTargetFaintAi(battlerAtk, battlerDef) - && IsBattlerFaster(AI_CHECK_SLOWER) + && IsAiFaster(AI_CHECK_SLOWER) && atkPriority > 0) score += 5; - // if target is evasive and this move damages/always hits, use it + // if target is evasive (or we have low accuracy)) and this move always hits, boost its score if (!IS_MOVE_STATUS(move) && gBattleMoves[move].accuracy == 0) { - if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 10) + if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 8) score++; - else if (gBattleMons[battlerAtk].statStages[STAT_ACC] <= 3) - score++; - else if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 7 && (Random() % 256) < 100) - score++; - else if (gBattleMons[battlerAtk].statStages[STAT_ACC] <= 4 && (Random() % 256 < 100)) + else if (gBattleMons[battlerAtk].statStages[STAT_ACC] <= 4) score++; } // prefer good damaging moves if (GetMoveDamageResult(move) == MOVE_POWER_BEST) score += 2; - else if (GetMoveDamageResult(move) == MOVE_POWER_GOOD && (Random() % 256) < 100) - score++; - + // check status move preference if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_PREFER_STATUS_MOVES && IS_MOVE_STATUS(move)) score++; @@ -4393,26 +4410,42 @@ static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (TestMoveFlags(move, FLAG_HIGH_CRIT) && effectiveness >= AI_EFFECTIVENESS_x2) score++; + // check thawing moves + if ((gBattleMons[battlerAtk].status1 & STATUS1_FREEZE) && IsThawingMove(move)) + score += (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) ? 20 : 10; + + // ability checks + switch (AI_DATA->atkAbility) + { + case ABILITY_MOXIE: + case ABILITY_BEAST_BOOST: + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + { + if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + score += 8; // prioritize killing target for stat boost + } + break; + } // ability checks + + // move effect checks switch (moveEffect) { case EFFECT_HIT: break; case EFFECT_SLEEP: case EFFECT_YAWN: - if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) - score++; - if ((HasMoveEffect(battlerAtk, EFFECT_DREAM_EATER) || HasMoveEffect(battlerAtk, EFFECT_NIGHTMARE)) && - !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) - score++; + IncreaseSleepScore(battlerAtk, battlerDef, move, &score); break; case EFFECT_DREAM_EATER: if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) break; - score++; // if target is asleep, dream eater is a pretty good move already + score++; // if target is asleep, dream eater is a pretty good move even without draining // fallthrough case EFFECT_ABSORB: - if (ShouldRecover(battlerAtk, battlerDef, move, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex])) + if (ShouldAbsorb(battlerAtk, battlerDef, move, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex])) score += 2; + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT) + score++; break; case EFFECT_EXPLOSION: case EFFECT_MEMENTO: @@ -4428,432 +4461,1478 @@ static u8 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_ATTACK_UP: case EFFECT_ATTACK_UP_2: - if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && GetHealthPercentage(battlerAtk) > 40 && AI_DATA->atkAbility != ABILITY_CONTRARY) - { - if (gBattleMons[battlerAtk].statStages[STAT_ATK] < 8) - score += 2; - else if (gBattleMons[battlerAtk].statStages[STAT_ATK] < 11) - score++; - } + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score); break; case EFFECT_DEFENSE_UP: case EFFECT_DEFENSE_UP_2: - if ((HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL) || IS_MOVE_PHYSICAL(gLastMoves[battlerDef])) && GetHealthPercentage(battlerAtk) > 70 && AI_DATA->atkAbility != ABILITY_CONTRARY) - { - if (gBattleMons[battlerAtk].statStages[STAT_DEF] < 8) - score += 2; // seems better to raise def at higher HP - else if (gBattleMons[battlerAtk].statStages[STAT_DEF] < 10) - score++; - } + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score); break; - case EFFECT_SPEED_UP: + case EFFECT_SPEED_UP: case EFFECT_SPEED_UP_2: - if (IsBattlerFaster(AI_CHECK_SLOWER) && AI_DATA->atkAbility != ABILITY_CONTRARY) - score += 3; + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score); break; - case EFFECT_SPECIAL_ATTACK_UP: + case EFFECT_SPECIAL_ATTACK_UP: case EFFECT_SPECIAL_ATTACK_UP_2: - if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && GetHealthPercentage(battlerAtk) > 40 && AI_DATA->atkAbility != ABILITY_CONTRARY) - { - if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < 8) - score += 2; - else if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < 11) - score++; - } + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score); break; - case EFFECT_SPECIAL_DEFENSE_UP: + case EFFECT_SPECIAL_DEFENSE_UP: case EFFECT_SPECIAL_DEFENSE_UP_2: - if ((HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) || IS_MOVE_SPECIAL(gLastMoves[battlerDef])) && GetHealthPercentage(battlerAtk) > 70 && AI_DATA->atkAbility != ABILITY_CONTRARY) - { - if (gBattleMons[battlerAtk].statStages[STAT_SPDEF] < 8) - score += 2; // seems better to raise spdef at higher HP - else if (gBattleMons[battlerAtk].statStages[STAT_SPDEF] < 10) - score++; - } + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score); break; case EFFECT_ACCURACY_UP: case EFFECT_ACCURACY_UP_2: - if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move)) - score += 3; // has moves with less than 80% accuracy - else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move)) - score += 2; + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ACC, &score); break; - case EFFECT_EVASION_UP: + case EFFECT_EVASION_UP: case EFFECT_EVASION_UP_2: case EFFECT_MINIMIZE: - if (AI_DATA->atkAbility != ABILITY_CONTRARY && !BattlerWillFaintFromWeather(battlerAtk, AI_DATA->atkAbility)) - { - if (!BattlerHasSecondaryDamage(battlerAtk) && !(gStatuses3[battlerAtk] & STATUS3_ROOTED)) - score += 3; - else - score += 2; - } + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_EVASION, &score); break; case EFFECT_ACUPRESSURE: break; - case EFFECT_ATTACK_ACCURACY_UP: // hone claws + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ACC, &score); break; - case EFFECT_GROWTH: case EFFECT_ATTACK_SPATK_UP: // work up - break; + if (GetHealthPercentage(battlerAtk) <= 40 || AI_DATA->atkAbility == ABILITY_CONTRARY) + break; - case EFFECT_ATTACK_DOWN: + if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score); + else if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score); + break; + case EFFECT_ATTACK_DOWN: case EFFECT_ATTACK_DOWN_2: if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) score += 2; break; - case EFFECT_DEFENSE_DOWN: + case EFFECT_DEFENSE_DOWN: case EFFECT_DEFENSE_DOWN_2: - //AI_CV_DefenseDown + if (ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + score += 2; break; - case EFFECT_SPEED_DOWN: + case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN_2: - //AI_CV_SpeedDown + if (ShouldLowerSpeed(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + score += 3; break; - case EFFECT_SPECIAL_ATTACK_DOWN: + case EFFECT_SPECIAL_ATTACK_DOWN: case EFFECT_SPECIAL_ATTACK_DOWN_2: - //AI_CV_SpAtkDown + if (ShouldLowerSpAtk(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + score += 2; break; - case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN: case EFFECT_SPECIAL_DEFENSE_DOWN_2: - //AI_CV_SpDefDown + if (ShouldLowerSpDef(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + score += 2; break; - case EFFECT_ACCURACY_DOWN: + case EFFECT_ACCURACY_DOWN: case EFFECT_ACCURACY_DOWN_2: - //AI_CV_AccuracyDown + if (ShouldLowerAccuracy(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + score += 4; break; - case EFFECT_EVASION_DOWN: + case EFFECT_EVASION_DOWN: case EFFECT_EVASION_DOWN_2: - //AI_CV_EvasionDown + if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + { + // kinda meh effect, so let's make sure we really want to + if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 7 + || HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + score += 2; // encourage lowering evasion if they are evasive or we have a move with low accuracy + else + score++; + } break; - case EFFECT_HAZE: - //AI_CV_Hazes + case EFFECT_HAZE: + if (AnyStatIsRaised(AI_DATA->battlerAtkPartner) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + break; + // fallthrough + case EFFECT_ROAR: + case EFFECT_CLEAR_SMOG: + if (isDoubleBattle) + score += min(CountPositiveStatStages(battlerDef) + CountPositiveStatStages(AI_DATA->battlerDefPartner), 7); + else + score += min(CountPositiveStatStages(battlerDef), 4); break; - case EFFECT_BIDE: - //AI_CV_Bide + case EFFECT_BIDE: break; - case EFFECT_ROAR: - //AI_CV_Roar + case EFFECT_MULTI_HIT: + case EFFECT_DOUBLE_HIT: + case EFFECT_TRIPLE_KICK: break; - case EFFECT_CONVERSION: - //AI_CV_Conversion + case EFFECT_CONVERSION: + if (!IS_BATTLER_OF_TYPE(battlerAtk, gBattleMoves[gBattleMons[battlerAtk].moves[0]].type)) + score++; break; - case EFFECT_RESTORE_HP: - //AI_CV_Heal + case EFFECT_FLINCH_HIT: + score += ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, move); break; - case EFFECT_SOFTBOILED: - //AI_CV_Heal + 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)) + score += 2; + } break; - case EFFECT_SWALLOW: - //AI_CV_Heal + 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)) + score += 3; + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT) + score++; break; - case EFFECT_ROOST: - //AI_CV_Heal - break; - case EFFECT_TOXIC: - //AI_CV_Toxic - break; - case EFFECT_LIGHT_SCREEN: - //AI_CV_LightScreen - break; - case EFFECT_REST: - //AI_CV_Rest - break; - case EFFECT_OHKO: - //AI_CV_OneHitKO - break; - case EFFECT_SUPER_FANG: - //AI_CV_SuperFang - break; - case EFFECT_TRAP: - //AI_CV_Trap - break; - case EFFECT_CONFUSE: - //AI_CV_Confuse - break; - case EFFECT_FOCUS_ENERGY: - //AI_CV_FocusEnergy + case EFFECT_TOXIC: + case EFFECT_POISON: + IncreasePoisonScore(battlerAtk, battlerDef, move, &score); break; + case EFFECT_LIGHT_SCREEN: case EFFECT_REFLECT: - //AI_CV_Reflect - break; - case EFFECT_AURORA_VEIL: - //AI_CV_AuroraVeil - break; - case EFFECT_POISON: - //AI_CV_Poison - break; - case EFFECT_TOXIC_THREAD: - //AI_CV_ToxicThread - break; - case EFFECT_PARALYZE: - //AI_CV_Paralyze - break; - case EFFECT_SWAGGER: - //AI_CV_Swagger - break; - case EFFECT_SPEED_DOWN_HIT: - //AI_CV_SpeedDownFromChance - break; - case EFFECT_TWO_TURNS_ATTACK: - //AI_CV_ChargeUpMove - break; - case EFFECT_VITAL_THROW: - //AI_CV_VitalThrow - break; - case EFFECT_SUBSTITUTE: - //AI_CV_Substitute - break; - case EFFECT_RECHARGE: - //AI_CV_Recharge - break; - case EFFECT_LEECH_SEED: - //AI_CV_LeechSeed - break; - case EFFECT_DISABLE: - //AI_CV_Disable - break; - case EFFECT_COUNTER: - //AI_CV_Counter - break; - case EFFECT_ENCORE: - //AI_CV_Encore - break; - case EFFECT_PAIN_SPLIT: - //AI_CV_PainSplit - break; - case EFFECT_LOCK_ON: - //AI_CV_LockOn - break; - case EFFECT_SLEEP_TALK: - //AI_CV_SleepTalk - break; - case EFFECT_SNORE: - //AI_CV_SleepTalk - break; - case EFFECT_DESTINY_BOND: - //AI_CV_DestinyBond - break; - case EFFECT_FLAIL: - //AI_CV_Flail - break; - case EFFECT_HEAL_BELL: - //AI_CV_HealBell - break; - case EFFECT_THIEF: - //AI_CV_Thief - break; - case EFFECT_MEAN_LOOK: - //AI_CV_Trap - break; - case EFFECT_CURSE: - //AI_CV_Curse - break; - case EFFECT_PROTECT: - //AI_CV_Protect - break; - case EFFECT_FORESIGHT: - //AI_CV_Foresight - break; - case EFFECT_ENDURE: - //AI_CV_Endure - break; - case EFFECT_BATON_PASS: - //AI_CV_BatonPass - break; - case EFFECT_PURSUIT: - //AI_CV_Pursuit - break; - case EFFECT_MORNING_SUN: - //AI_CV_HealWeather - break; - case EFFECT_SYNTHESIS: - //AI_CV_HealWeather - break; - case EFFECT_MOONLIGHT: - //AI_CV_HealWeather - break; - case EFFECT_SHORE_UP: - //AI_CV_Heal - break; - case EFFECT_RAIN_DANCE: - //AI_CV_RainDance - break; - case EFFECT_SUNNY_DAY: - //AI_CV_SunnyDay - break; - case EFFECT_BELLY_DRUM: - //AI_CV_BellyDrum - break; - case EFFECT_PSYCH_UP: - //AI_CV_PsychUp - break; - case EFFECT_MIRROR_COAT: - //AI_CV_MirrorCoat - break; - case EFFECT_SKULL_BASH: - //AI_CV_ChargeUpMove - break; - case EFFECT_SOLARBEAM: - //AI_CV_ChargeUpMove - break; - break; - case EFFECT_GEOMANCY: - //AI_CV_Geomancy - break; - case EFFECT_SEMI_INVULNERABLE: - //AI_CV_SemiInvulnerable - break; - case EFFECT_FAKE_OUT: - //AI_CV_FakeOut - break; - case EFFECT_SPIT_UP: - //AI_CV_SpitUp - break; - case EFFECT_HAIL: - //AI_CV_Sandstorm - break; - case EFFECT_SANDSTORM: - //AI_CV_Sandstorm - break; - case EFFECT_FLATTER: - //AI_CV_Flatter - break; - case EFFECT_FACADE: - //AI_CV_Facade - break; - case EFFECT_FOCUS_PUNCH: - //AI_CV_FocusPunch - break; - case EFFECT_SMELLINGSALT: - //AI_CV_SmellingSalt - break; - case EFFECT_TRICK: - //AI_CV_Trick - break; - case EFFECT_ROLE_PLAY: - //AI_CV_ChangeSelfAbility - break; - case EFFECT_SUPERPOWER: - //AI_CV_Superpower - break; - case EFFECT_MAGIC_COAT: - //AI_CV_MagicCoat - break; - case EFFECT_RECYCLE: - //AI_CV_Recycle - break; - case EFFECT_REVENGE: - //AI_CV_Revenge - break; - case EFFECT_BRICK_BREAK: - //AI_CV_BrickBreak - break; - case EFFECT_KNOCK_OFF: - //AI_CV_KnockOff - break; - case EFFECT_ENDEAVOR: - //AI_CV_Endeavor - break; - case EFFECT_ERUPTION: - //AI_CV_Eruption - break; - case EFFECT_SKILL_SWAP: - //AI_CV_ChangeSelfAbility - break; - case EFFECT_IMPRISON: - //AI_CV_Imprison - break; - case EFFECT_REFRESH: - //AI_CV_Refresh - break; - case EFFECT_SNATCH: - //AI_CV_Snatch - break; - case EFFECT_MUD_SPORT: - //AI_CV_MudSport - break; - case EFFECT_OVERHEAT: - //AI_CV_Overheat - break; - case EFFECT_TICKLE: - //AI_CV_DefenseDown - break; - case EFFECT_COSMIC_POWER: - //AI_CV_SpDefUp - break; - case EFFECT_BULK_UP: - //AI_CV_DefenseUp - break; - case EFFECT_WATER_SPORT: - //AI_CV_WaterSport - break; - case EFFECT_CALM_MIND: - //AI_CV_SpDefUp - break; - case EFFECT_DRAGON_DANCE: - //AI_CV_DragonDance - break; - case EFFECT_POWDER: - //AI_CV_Powder - break; - case EFFECT_MISTY_TERRAIN: - //AI_CV_MistyTerrain - break; - case EFFECT_GRASSY_TERRAIN: - //AI_CV_GrassyTerrain - break; - case EFFECT_ELECTRIC_TERRAIN: - //AI_CV_ElectricTerrain - break; - case EFFECT_PSYCHIC_TERRAIN: - //AI_CV_PsychicTerrain - break; - case EFFECT_STEALTH_ROCK: - //AI_CV_Hazards - break; - case EFFECT_SPIKES: - //AI_CV_Hazards - break; - case EFFECT_STICKY_WEB: - //AI_CV_Hazards - break; - case EFFECT_TOXIC_SPIKES: - //AI_CV_Hazards - break; - case EFFECT_PERISH_SONG: - //AI_CV_PerishSong - break; + case EFFECT_AURORA_VEIL: + if (ShouldSetScreen(battlerAtk, battlerDef, move)) + { + score += 5; + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_LIGHT_CLAY) + score += 2; + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SCREENER) + score += 2; + } + break; + case EFFECT_REST: + if (!(CanSleep(battlerAtk, AI_DATA->atkAbility))) + { + break; + } + else if (ShouldRecover(battlerAtk, battlerDef, move, 100)) + { + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_CURE_SLP + || AI_DATA->atkHoldEffect == HOLD_EFFECT_CURE_STATUS + || HasMoveEffect(EFFECT_SLEEP_TALK, battlerAtk) + || HasMoveEffect(EFFECT_SNORE, battlerAtk) + || AI_DATA->atkAbility == ABILITY_SHED_SKIN + || AI_DATA->atkAbility == ABILITY_EARLY_BIRD + || (gBattleWeather & WEATHER_RAIN_ANY && gWishFutureKnock.weatherDuration != 1 && AI_DATA->atkAbility == ABILITY_HYDRATION && AI_DATA->atkHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA)) + { + score += 2; + } + else + { + score++; + } + } + break; + case EFFECT_OHKO: + if (gStatuses3[battlerAtk] & STATUS3_ALWAYS_HITS) + score += 5; + break; + case EFFECT_TRAP: + case EFFECT_MEAN_LOOK: + if (HasMoveEffect(battlerDef, EFFECT_RAPID_SPIN) + || IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) + || gBattleMons[battlerDef].status2 & STATUS2_WRAPPED) + { + break; // in this case its a bad attacking move + } + else if (ShouldTrap(battlerAtk, battlerDef, move)) + { + score += 5; + } + break; + case EFFECT_MIST: + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SCREENER) + score += 2; + break; + case EFFECT_FOCUS_ENERGY: + case EFFECT_LASER_FOCUS: + if (AI_DATA->atkAbility == ABILITY_SUPER_LUCK + || AI_DATA->atkAbility == ABILITY_SNIPER + || AI_DATA->atkHoldEffect == HOLD_EFFECT_SCOPE_LENS + || TestMoveFlagsInMoveset(battlerAtk, FLAG_HIGH_CRIT)) + score += 2; + break; + case EFFECT_CONFUSE_HIT: + if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE) + score++; + //fallthrough + case EFFECT_CONFUSE: + IncreaseConfusionScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_PARALYZE: + IncreaseParalyzeScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_ATTACK_DOWN_HIT: + case EFFECT_DEFENSE_DOWN_HIT: + case EFFECT_SPECIAL_ATTACK_DOWN_HIT: + case EFFECT_SPECIAL_DEFENSE_DOWN_HIT: + case EFFECT_ACCURACY_DOWN_HIT: + case EFFECT_EVASION_DOWN_HIT: + if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY) + score += 2; + break; + case EFFECT_SPEED_DOWN_HIT: + if (ShouldLowerSpeed(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + { + if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY) + score += 4; + else + score += 2; + } + break; + case EFFECT_SUBSTITUTE: + if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) + score += 3; + if (gBattleMons[battlerDef].status1 & (STATUS1_BURN | STATUS1_PSN_ANY)) + score++; + 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)) + score += 2; + if (!gBattleMons[battlerDef].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION && GetHealthPercentage(battlerAtk) > 70)) + score++; + break; + case EFFECT_MIMIC: + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) + { + if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF) + return AI_CheckGoodMove(battlerAtk, battlerDef, gLastMoves[battlerDef], score); + } + break; + case EFFECT_LEECH_SEED: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) + || gStatuses3[battlerDef] & STATUS3_LEECHSEED + || HasMoveEffect(battlerDef, EFFECT_RAPID_SPIN) + || AI_DATA->defAbility == ABILITY_LIQUID_OOZE + || AI_DATA->defAbility == ABILITY_MAGIC_GUARD) + break; + score += 3; + if (!HasDamagingMove(battlerDef) || IsBattlerTrapped(battlerDef, FALSE)) + score += 2; + break; + case EFFECT_DO_NOTHING: + //todo - check z splash, z celebrate, z happy hour (lol) + break; + case EFFECT_TELEPORT: + 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, AI_DATA->defAbility, move, AI_THINKING_STRUCT->movesetIndex)) + { + case 0: // no + score -= 10; // technically should go in CheckBadMove, but this is easier/less computationally demanding + break; + case 1: // maybe + break; + case 2: // yes + score += 7; + break; + } + } + else //Double Battle + { + if (CountUsablePartyMons(battlerAtk) == 0) + break; // Can't switch + + //if (switchAbility == ABILITY_INTIMIDATE && PartyHasMoveSplit(battlerDef, SPLIT_PHYSICAL)) + //score += 7; + } + break; + case EFFECT_BATON_PASS: + if (ShouldSwitch() && (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE + || (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING | STATUS3_MAGNET_RISE | STATUS3_POWER_TRICK)) + || AnyStatIsRaised(battlerAtk))) + score += 5; + break; + case EFFECT_DISABLE: + if (gDisableStructs[battlerDef].disableTimer == 0 + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_ATTRACT)) // mental herb + { + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // AI goes first + { + if (gLastMoves[battlerDef] != MOVE_NONE + && gLastMoves[battlerDef] != 0xFFFF) + { + /* TODO predicted moves + if (gLastMoves[battlerDef] == predictedMove) + score += 3; + else */if (CanMoveFaintBattler(gLastMoves[battlerDef], battlerDef, battlerAtk, 1)) + score += 2;; //Disable move that can kill attacker + } + } + else if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove)) + { + score++; // Disable annoying status moves + } + } + break; + case EFFECT_ENCORE: + if (gDisableStructs[battlerDef].encoreTimer == 0 + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_ATTRACT)) // mental herb + { + if (IsEncoreEncouragedEffect(gBattleMoves[gLastMoves[battlerDef]].effect)) + score += 3; + } + break; + case EFFECT_PAIN_SPLIT: + { + u16 newHp = (gBattleMons[battlerAtk].hp + gBattleMons[battlerDef].hp) / 2; + u16 healthBenchmark = (gBattleMons[battlerAtk].hp * 12) / 10; + if (newHp > healthBenchmark && ShouldAbsorb(battlerAtk, battlerDef, move, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex])) + score += 2; + } + break; + case EFFECT_SLEEP_TALK: + case EFFECT_SNORE: + if (!IsWakeupTurn(battlerAtk) && gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) + score += 10; + break; + case EFFECT_LOCK_ON: + if (HasMoveEffect(battlerAtk, EFFECT_OHKO)) + score += 3; + else if (AI_DATA->atkAbility == ABILITY_COMPOUND_EYES && HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + score += 3; + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 85, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + score += 3; + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + score++; + break; + case EFFECT_SPEED_UP_HIT: + if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY && IsAiFaster(AI_CHECK_SLOWER)) + score += 3; + break; + case EFFECT_DESTINY_BOND: + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && CanTargetFaintAi(battlerDef, battlerAtk)) + score += 3; + break; + case EFFECT_SPITE: + //TODO - predicted move + break; + case EFFECT_WISH: + case EFFECT_HEAL_BELL: + if (ShouldUseWishAromatherapy(battlerAtk, battlerDef, move)) + score += 7; + break; + case EFFECT_THIEF: + { + bool32 canSteal = FALSE; + + #if defined B_TRAINERS_KNOCK_OFF_ITEMS && B_TRAINERS_KNOCK_OFF_ITEMS == TRUE + canSteal = TRUE; + #endif + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER || GetBattlerSide(battlerAtk) == B_SIDE_PLAYER) + canSteal = TRUE; + + if (canSteal && AI_DATA->atkItem == ITEM_NONE + && AI_DATA->defItem != ITEM_NONE + && CanBattlerGetOrLoseItem(battlerDef, AI_DATA->defItem) + && CanBattlerGetOrLoseItem(battlerAtk, AI_DATA->defItem) + && !HasMoveEffect(battlerAtk, EFFECT_ACROBATICS) + && AI_DATA->defAbility != ABILITY_STICKY_HOLD) + { + switch (AI_DATA->defHoldEffect) + { + case HOLD_EFFECT_NONE: + break; + case HOLD_EFFECT_CHOICE_BAND: + case HOLD_EFFECT_CHOICE_SCARF: + case HOLD_EFFECT_CHOICE_SPECS: + score += 2; + break; + case HOLD_EFFECT_TOXIC_ORB: + if (ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility)) + score += 2; + break; + case HOLD_EFFECT_FLAME_ORB: + if (ShouldBurnSelf(battlerAtk, AI_DATA->atkAbility)) + score += 2; + break; + case HOLD_EFFECT_BLACK_SLUDGE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON)) + score += 2; + break; + case HOLD_EFFECT_IRON_BALL: + if (HasMoveEffect(battlerAtk, EFFECT_FLING)) + score += 2; + break; + case HOLD_EFFECT_LAGGING_TAIL: + case HOLD_EFFECT_STICKY_BARB: + break; + default: + score++; + break; + } + } + break; + } + break; + case EFFECT_NIGHTMARE: + if (AI_DATA->defAbility != ABILITY_MAGIC_GUARD + && !(gBattleMons[battlerDef].status2 & STATUS2_NIGHTMARE) + && (AI_DATA->defAbility == ABILITY_COMATOSE || gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) + { + score += 5; + if (IsBattlerTrapped(battlerDef, TRUE)) + score += 3; + } + break; + case EFFECT_CURSE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) + { + if (IsBattlerTrapped(battlerDef, TRUE)) + score += 3; + else + score++; + break; + } + else + { + if (AI_DATA->atkAbility == ABILITY_CONTRARY || AI_DATA->defAbility == ABILITY_MAGIC_GUARD) + break; + else if (gBattleMons[battlerAtk].statStages[STAT_ATK] < 8) + score += (8 - gBattleMons[battlerAtk].statStages[STAT_ATK]); + else if (gBattleMons[battlerAtk].statStages[STAT_SPEED] < 3) + break; + else if (gBattleMons[battlerAtk].statStages[STAT_DEF] < 8) + score += (8 - gBattleMons[battlerAtk].statStages[STAT_DEF]); + } + break; + case EFFECT_PROTECT: + if (predictedMove == 0xFFFF) + predictedMove = MOVE_NONE; + switch (move) + { + case MOVE_QUICK_GUARD: + if (predictedMove != MOVE_NONE && gBattleMoves[predictedMove].priority > 0) + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + break; + case MOVE_WIDE_GUARD: + if (predictedMove != MOVE_NONE && gBattleMoves[predictedMove].target & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH)) + { + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + } + else if (isDoubleBattle && gBattleMoves[AI_DATA->partnerMove].target & MOVE_TARGET_FOES_AND_ALLY) + { + if (AI_DATA->atkAbility != ABILITY_TELEPATHY) + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + } + break; + case MOVE_CRAFTY_SHIELD: + if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove) && !(gBattleMoves[predictedMove].target & 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) && !(gBattleMoves[predictedMove].target & MOVE_TARGET_USER)) + ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); + break; + case MOVE_KINGS_SHIELD: + #if (defined SPECIES_AEGISLASH && defined SPECIES_AEGISLASH_BLADE) + if (AI_DATA->atkAbility == ABILITY_STANCE_CHANGE //Special logic for Aegislash + && AI_DATA->atkSpecies == SPECIES_AEGISLASH_BLADE + && !IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility)) + { + score += 3; + break; + } + #endif + //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(AI_DATA->atkHoldEffect)) + { + score += 3; + } + else if (gBattleMons[battlerAtk].hp > 1) // Only spam endure for Flail/Reversal if you're not at Min Health + { + if (HasMoveEffect(battlerAtk, EFFECT_FLAIL) || HasMoveEffect(battlerAtk, EFFECT_ENDEAVOR)) + score += 3; + } + } + break; + + case EFFECT_SPIKES: + case EFFECT_STEALTH_ROCK: + case EFFECT_STICKY_WEB: + case EFFECT_TOXIC_SPIKES: + if (AI_DATA->defAbility == ABILITY_MAGIC_BOUNCE || CountUsablePartyMons(battlerDef) == 0) + break; + if (gDisableStructs[battlerAtk].isFirstTurn) + score += 2; + //TODO - track entire opponent party data to determine hazard effectiveness + break; + case EFFECT_FORESIGHT: + if (AI_DATA->atkAbility == ABILITY_SCRAPPY) + 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)))) + score += 2; + 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)))) + score += 2; + break; + case EFFECT_PERISH_SONG: + if (IsBattlerTrapped(battlerDef, TRUE)) + score += 3; + break; + case EFFECT_SANDSTORM: + if (ShouldSetSandstorm(battlerAtk, AI_DATA->atkHoldEffect, AI_DATA->atkHoldEffect)) + { + score++; + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_SMOOTH_ROCK) + score++; + if (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) + && ShouldSetSandstorm(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, AI_DATA->atkPartnerHoldEffect)) + score += 2; + } + break; + case EFFECT_HAIL: + if (ShouldSetHail(battlerAtk, AI_DATA->atkAbility, AI_DATA->atkHoldEffect)) + { + if ((HasMoveEffect(battlerAtk, EFFECT_AURORA_VEIL) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_AURORA_VEIL)) + && ShouldSetScreen(battlerAtk, battlerDef, EFFECT_AURORA_VEIL)) + score += 3; + + score++; + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_ICY_ROCK) + score++; + if (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) + && ShouldSetHail(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, AI_DATA->atkPartnerHoldEffect)) + score += 2; + if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) + || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) + || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) + score += 2; + } + break; + case EFFECT_RAIN_DANCE: + if (ShouldSetRain(battlerAtk, AI_DATA->atkAbility, AI_DATA->atkHoldEffect)) + { + score++; + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_DAMP_ROCK) + score++; + if (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) + && ShouldSetRain(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, AI_DATA->atkPartnerHoldEffect)) + score += 2; + if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) + || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) + || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) + score += 2; + if (HasMoveWithType(battlerDef, TYPE_FIRE) || HasMoveWithType(AI_DATA->battlerDefPartner, TYPE_FIRE)) + score++; + } + break; + case EFFECT_SUNNY_DAY: + if (ShouldSetSun(battlerAtk, AI_DATA->atkAbility, AI_DATA->atkHoldEffect)) + { + score++; + if (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) + && ShouldSetSun(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, AI_DATA->atkPartnerHoldEffect)) + score += 2; // partner also gets sunlight benefit + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_HEAT_ROCK) + score++; + if (HasMoveWithType(battlerDef, TYPE_WATER) || HasMoveWithType(AI_DATA->battlerDefPartner, TYPE_WATER)) + score++; + if (HasMoveEffect(battlerDef, EFFECT_THUNDER) || HasMoveEffect(AI_DATA->battlerDefPartner, EFFECT_THUNDER)) + score++; + } + break; + case EFFECT_ATTACK_UP_HIT: + if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE) + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score); + break; + case EFFECT_FELL_STINGER: + if (gBattleMons[battlerAtk].statStages[STAT_ATK] < MAX_STAT_STAGE + && AI_DATA->atkAbility != ABILITY_CONTRARY + && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + { + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first + score += 9; + else + score += 3; + } + break; + case EFFECT_BELLY_DRUM: + if (!CanTargetFaintAi(battlerDef, battlerAtk) && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && AI_DATA->atkAbility != ABILITY_CONTRARY) + score += (MAX_STAT_STAGE - gBattleMons[battlerAtk].statStages[STAT_ATK]); + break; + case EFFECT_PSYCH_UP: + case EFFECT_SPECTRAL_THIEF: + // 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: + if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + score++; + break; + case STAT_SPATK: + if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + score++; + break; + case STAT_ACC: + case STAT_EVASION: + case STAT_SPEED: + score++; + break; + case STAT_DEF: + case STAT_SPDEF: + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL) + score++; + break; + } + } + } + break; + case EFFECT_SEMI_INVULNERABLE: + score++; + if (predictedMove != MOVE_NONE && !isDoubleBattle) + { + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first + { + if (gBattleMoves[predictedMove].effect == EFFECT_EXPLOSION + || gBattleMoves[predictedMove].effect == EFFECT_PROTECT) + score += 3; + } + else if (gBattleMoves[predictedMove].effect == EFFECT_SEMI_INVULNERABLE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE)) + { + score += 3; + } + } + break; + case EFFECT_DEFENSE_CURL: + if (HasMoveEffect(battlerAtk, EFFECT_ROLLOUT) && !(gBattleMons[battlerAtk].status2 & STATUS2_DEFENSE_CURL)) + score++; + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score); + break; + case EFFECT_FAKE_OUT: + if (move == MOVE_FAKE_OUT // filter out first impression + && ShouldFakeOut(battlerAtk, battlerDef, move)) + score += 8; + break; + case EFFECT_STOCKPILE: + if (AI_DATA->atkAbility == ABILITY_CONTRARY) + break; + if (HasMoveEffect(battlerAtk, EFFECT_SWALLOW) + || HasMoveEffect(battlerAtk, EFFECT_SPIT_UP)) + score += 2; + + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score); + break; + case EFFECT_SPIT_UP: + if (gDisableStructs[battlerAtk].stockpileCounter >= 2) + score++; + break; + case EFFECT_ROLLOUT: + if (gBattleMons[battlerAtk].status2 & STATUS2_DEFENSE_CURL) + score += 8; + break; + case EFFECT_SWAGGER: + if (HasMoveEffect(battlerAtk, EFFECT_FOUL_PLAY) + || HasMoveEffect(battlerAtk, EFFECT_PSYCH_UP) + || HasMoveEffect(battlerAtk, EFFECT_SPECTRAL_THIEF)) + score++; + + if (AI_DATA->defAbility == ABILITY_CONTRARY) + score += 2; + + IncreaseConfusionScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_FLATTER: + if (HasMoveEffect(battlerAtk, EFFECT_PSYCH_UP) + || HasMoveEffect(battlerAtk, EFFECT_SPECTRAL_THIEF)) + score += 2; + + if (AI_DATA->defAbility == ABILITY_CONTRARY) + score += 2; + + IncreaseConfusionScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_FURY_CUTTER: + if (!isDoubleBattle && AI_DATA->atkHoldEffect == HOLD_EFFECT_METRONOME) + score += 3; + break; + case EFFECT_ATTRACT: + if (!isDoubleBattle && BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->defAbility) + && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // Target goes first + 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)) + score += 2; + else + score++; + break; + case EFFECT_SAFEGUARD: + if (!(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) || !IsBattlerGrounded(battlerAtk)) + score++; + //if (CountUsablePartyMons(battlerDef) != 0) + //score += 8; + break; + case EFFECT_PURSUIT: + /*TODO + if (IsPredictedToSwitch(battlerDef, battlerAtk)) + score += 3; + else if (IsPredictedToUsePursuitableMove(battlerDef, battlerAtk) && !MoveWouldHitFirst(move, battlerAtk, battlerDef)) //Pursuit against fast U-Turn + score += 3;*/ + break; + case EFFECT_RAPID_SPIN: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score); // Gen 8 increases speed + //fallthrough + case EFFECT_DEFOG: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) + { + score += 3; + break; + } + + switch (move) + { + case MOVE_DEFOG: + if (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST)) + { + score += 3; + } + else if (!(gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SPIKES)) //Don't blow away hazards if you set them up + { + if (isDoubleBattle) + { + if (IsHazardMoveEffect(gBattleMoves[AI_DATA->partnerMove].effect) // Partner is going to set up hazards + && GetWhoStrikesFirst(battlerAtk, AI_DATA->battlerAtkPartner, TRUE) == 1) // Partner going first + break; // Don't use Defog if partner is going to set up hazards + } + + // check defog lowering evasion + if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + { + if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 7 + || HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + score += 2; // encourage lowering evasion if they are evasive or we have a move with low accuracy + else + score++; + } + } + break; + case MOVE_RAPID_SPIN: + if (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED) + score += 3; + break; + } + 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, AI_DATA->defAbility) + && (move != MOVE_RAGE_POWDER || IsAffectedByPowder(battlerDef, AI_DATA->defAbility, AI_DATA->defHoldEffect)) // Rage Powder doesn't affect powder immunities + && IsBattlerAlive(AI_DATA->battlerAtkPartner)) + { + u16 predictedMoveOnPartner = gLastMoves[AI_DATA->battlerAtkPartner]; + if (predictedMoveOnPartner != MOVE_NONE && !IS_MOVE_STATUS(predictedMoveOnPartner)) + score += 3; + } + break; + case EFFECT_NATURE_POWER: + return AI_CheckGoodMove(battlerAtk, battlerDef, GetNaturePowerMove(), score); + case EFFECT_CHARGE: + if (HasDamagingMoveOfType(battlerAtk, TYPE_ELECTRIC)) + score += 2; + + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score); + break; + case EFFECT_TAUNT: + if (IS_MOVE_STATUS(predictedMove)) + score += 3; + else if (HasMoveWithSplit(battlerDef, SPLIT_STATUS)) + score += 2; + break; + case EFFECT_TRICK: + case EFFECT_BESTOW: + switch (AI_DATA->atkHoldEffect) + { + case HOLD_EFFECT_CHOICE_SCARF: + score += 2; // assume its beneficial + break; + case HOLD_EFFECT_CHOICE_BAND: + if (!HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) + score += 2; + break; + case HOLD_EFFECT_CHOICE_SPECS: + if (!HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) + score += 2; + break; + case HOLD_EFFECT_TOXIC_ORB: + if (!ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility) && CanBePoisoned(battlerDef, AI_DATA->defAbility)) + score += 2; + break; + case HOLD_EFFECT_FLAME_ORB: + if (!ShouldBurnSelf(battlerAtk, AI_DATA->atkAbility) && CanBeBurned(battlerAtk, AI_DATA->defAbility)) + score += 2; + break; + case HOLD_EFFECT_BLACK_SLUDGE: + if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON) && AI_DATA->defAbility != ABILITY_MAGIC_GUARD) + score += 3; + break; + case HOLD_EFFECT_IRON_BALL: + if (!HasMoveEffect(battlerDef, EFFECT_FLING) || !IsBattlerGrounded(battlerDef)) + score += 2; + break; + case HOLD_EFFECT_LAGGING_TAIL: + case HOLD_EFFECT_STICKY_BARB: + score += 3; + break; + case HOLD_EFFECT_UTILITY_UMBRELLA: + if (AI_DATA->atkAbility != ABILITY_SOLAR_POWER && AI_DATA->atkAbility != ABILITY_DRY_SKIN && AI_WeatherHasEffect()) + { + switch (AI_DATA->defAbility) + { + case ABILITY_SWIFT_SWIM: + if (gBattleWeather & WEATHER_RAIN_ANY) + score += 3; // Slow 'em down + break; + case ABILITY_CHLOROPHYLL: + case ABILITY_FLOWER_GIFT: + if (gBattleWeather & WEATHER_SUN_ANY) + score += 3; // Slow 'em down + break; + } + } + break; + case HOLD_EFFECT_EJECT_BUTTON: + //if (!IsRaidBattle() && IsDynamaxed(battlerDef) && gNewBS->dynamaxData.timer[battlerDef] > 1 && + if (HasDamagingMove(battlerAtk) + || (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) && HasDamagingMove(AI_DATA->battlerAtkPartner))) + score += 2; // Force 'em out next turn + break; + default: + if (move != MOVE_BESTOW && AI_DATA->atkItem == ITEM_NONE) + { + switch (AI_DATA->defHoldEffect) + { + case HOLD_EFFECT_CHOICE_BAND: + break; + case HOLD_EFFECT_TOXIC_ORB: + if (ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility)) + score += 2; + break; + case HOLD_EFFECT_FLAME_ORB: + if (ShouldBurnSelf(battlerAtk, AI_DATA->atkAbility)) + score += 2; + break; + case HOLD_EFFECT_BLACK_SLUDGE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON) || AI_DATA->atkAbility == ABILITY_MAGIC_GUARD) + score += 3; + break; + case HOLD_EFFECT_IRON_BALL: + if (HasMoveEffect(battlerAtk, EFFECT_FLING)) + score += 2; + break; + case HOLD_EFFECT_LAGGING_TAIL: + case HOLD_EFFECT_STICKY_BARB: + break; + default: + score++; //other hold effects generally universally good + break; + } + } + } + break; + case EFFECT_ROLE_PLAY: + if (!IsRolePlayBannedAbilityAtk(AI_DATA->atkAbility) + && !IsRolePlayBannedAbility(AI_DATA->defAbility) + && !IsAbilityOfRating(AI_DATA->atkAbility, 5) + && IsAbilityOfRating(AI_DATA->defAbility, 5)) + score += 2; + break; + case EFFECT_INGRAIN: + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT) + score += 3; + else + score++; + break; + case EFFECT_SUPERPOWER: + case EFFECT_OVERHEAT: + if (AI_DATA->atkAbility == ABILITY_CONTRARY) + score += 10; + break; + case EFFECT_MAGIC_COAT: + if (IS_MOVE_STATUS(predictedMove) && gBattleMoves[predictedMove].target & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH)) + score += 3; + break; + case EFFECT_RECYCLE: + if (gBattleStruct->usedHeldItems[battlerAtk] != ITEM_NONE) + score++; + if (IsRecycleEncouragedItem(gBattleStruct->usedHeldItems[battlerAtk])) + score++; + break; + case EFFECT_BRICK_BREAK: + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_REFLECT) + score++; + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_LIGHTSCREEN) + score++; + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_AURORA_VEIL) + score++; + break; + case EFFECT_KNOCK_OFF: + if (CanKnockOffItem(battlerDef, AI_DATA->defItem)) + { + switch (AI_DATA->defHoldEffect) + { + case HOLD_EFFECT_IRON_BALL: + if (HasMoveEffect(battlerDef, EFFECT_FLING)) + score += 4; + break; + case HOLD_EFFECT_LAGGING_TAIL: + case HOLD_EFFECT_STICKY_BARB: + break; + default: + score += 3; + break; + } + } + break; + case EFFECT_SKILL_SWAP: + if (GetAbilityRating(AI_DATA->defAbility) > GetAbilityRating(AI_DATA->atkAbility)) + score++; + break; + case EFFECT_WORRY_SEED: + case EFFECT_GASTRO_ACID: + case EFFECT_SIMPLE_BEAM: + if (IsAbilityOfRating(AI_DATA->defAbility, 5)) + score += 2; + break; + case EFFECT_ENTRAINMENT: + if (IsAbilityOfRating(AI_DATA->defAbility, 5) || GetAbilityRating(AI_DATA->atkAbility) <= 0) + { + if (AI_DATA->defAbility != AI_DATA->atkAbility && !(gStatuses3[battlerDef] & STATUS3_GASTRO_ACID)) + score += 2; + } + break; + case EFFECT_IMPRISON: + if (predictedMove != MOVE_NONE && HasMove(battlerAtk, predictedMove)) + score += 3; + else if (gDisableStructs[battlerAtk].isFirstTurn == 0) + score++; + break; + case EFFECT_REFRESH: + if (gBattleMons[battlerAtk].status1 & STATUS1_ANY) + score += 2; + 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); + break; + case EFFECT_GRUDGE: + break; + case EFFECT_SNATCH: + if (predictedMove != MOVE_NONE && TestMoveFlags(predictedMove, FLAG_SNATCH_AFFECTED)) + score += 3; // Steal move + break; + case EFFECT_MUD_SPORT: + if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC) && HasMoveWithType(battlerDef, TYPE_ELECTRIC)) + score++; + break; + case EFFECT_WATER_SPORT: + if (!HasMoveWithType(battlerAtk, TYPE_FIRE) && (HasMoveWithType(battlerDef, TYPE_FIRE))) + score++; + break; + case EFFECT_TICKLE: + if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) + && AI_DATA->defAbility != ABILITY_CONTRARY && ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + { + score += 2; + } + else if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + { + score += 2; + } + break; + case EFFECT_COSMIC_POWER: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score); + break; + case EFFECT_BULK_UP: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score); + break; + case EFFECT_CALM_MIND: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score); + break; + case EFFECT_GEOMANCY: + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_POWER_HERB) + score += 3; + //fallthrough + case EFFECT_QUIVER_DANCE: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score); + break; + case EFFECT_SHELL_SMASH: + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_POWER_HERB) + score += 3; + + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score); + break; + case EFFECT_DRAGON_DANCE: + case EFFECT_SHIFT_GEAR: + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_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]) + score++; + else if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > gBattleMons[battlerAtk].statStages[STAT_SPDEF] + && gBattleMons[battlerDef].statStages[STAT_DEF] >= gBattleMons[battlerAtk].statStages[STAT_DEF]) + score++; + 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]) + score++; + else if (gBattleMons[battlerDef].statStages[STAT_SPATK] > gBattleMons[battlerAtk].statStages[STAT_SPATK] + && gBattleMons[battlerDef].statStages[STAT_ATK] >= gBattleMons[battlerAtk].statStages[STAT_ATK]) + score++; + break; + case EFFECT_POWER_TRICK: + if (!(gStatuses3[battlerAtk] & STATUS3_POWER_TRICK)) + { + if (gBattleMons[battlerAtk].defense > gBattleMons[battlerAtk].attack && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + score += 2; + break; + } + 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) + score++; + } + break; + case EFFECT_SPEED_SWAP: + // TODO this is cheating a bit... + if (gBattleMons[battlerDef].speed > gBattleMons[battlerAtk].speed) + score += 3; + break; + case EFFECT_GUARD_SPLIT: + { + // TODO also kind of cheating... + u16 newDefense = (gBattleMons[battlerAtk].defense + gBattleMons[battlerDef].defense) / 2; + u16 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)) + score++; + } + break; + case EFFECT_POWER_SPLIT: + { + u16 newAttack = (gBattleMons[battlerAtk].attack + gBattleMons[battlerDef].attack) / 2; + u16 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)) + score++; + } + break; + case EFFECT_BUG_BITE: // And pluck + if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || AI_DATA->defAbility == ABILITY_STICKY_HOLD) + break; + else if (ItemId_GetPocket(AI_DATA->defItem) == POCKET_BERRIES) + score += 3; + break; + case EFFECT_INCINERATE: + if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || AI_DATA->defAbility == ABILITY_STICKY_HOLD) + break; + else if (ItemId_GetPocket(AI_DATA->defItem) == POCKET_BERRIES || AI_DATA->defHoldEffect == HOLD_EFFECT_GEMS) + score += 3; + break; + case EFFECT_SMACK_DOWN: + if (!IsBattlerGrounded(battlerDef)) + score += 3; + break; + case EFFECT_SLEEP_HIT: // Relic Song + #if (defined SPECIES_MELOETTA && defined SPECIES_MELOETTA_PIROUETTE) + if (AI_DATA->atkSpecies == SPECIES_MELOETTA && gBattleMons[battlerDef].defense < gBattleMons[battlerDef].spDefense) + score += 3; // Change to pirouette if can do more damage + else if (AI_DATA->atkSpecies == SPECIES_MELOETTA_PIROUETTE && gBattleMons[battlerDef].spDefense < gBattleMons[battlerDef].defense) + score += 3; // Change to Aria if can do more damage + #endif + break; + case EFFECT_ELECTRIC_TERRAIN: + case EFFECT_MISTY_TERRAIN: + if (gStatuses3[battlerAtk] & STATUS3_YAWN && IsBattlerGrounded(battlerAtk)) + score += 10; + //fallthrough + case EFFECT_GRASSY_TERRAIN: + case EFFECT_PSYCHIC_TERRAIN: + score += 2; + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_TERRAIN_EXTENDER) + score += 2; + break; + case EFFECT_PLEDGE: + if (isDoubleBattle) + { + if (HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_PLEDGE)) + score += 3; // Partner might use pledge move + } + break; + case EFFECT_TRICK_ROOM: + if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) + score += 3; + else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) >= GetBattlerSideSpeedAverage(battlerDef)) + score += 3; + break; + case EFFECT_MAGIC_ROOM: + score++; + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_NONE && AI_DATA->defHoldEffect != HOLD_EFFECT_NONE) + score++; + if (isDoubleBattle && AI_DATA->atkPartnerHoldEffect == HOLD_EFFECT_NONE && AI_DATA->defPartnerHoldEffect != HOLD_EFFECT_NONE) + score++; + break; + case EFFECT_WONDER_ROOM: + if ((HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL) && gBattleMons[battlerAtk].defense < gBattleMons[battlerAtk].spDefense) + || (HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) && gBattleMons[battlerAtk].spDefense < gBattleMons[battlerAtk].defense)) + score += 2; + 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); + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + score += 2; + else + score++; + } + break; + case EFFECT_ION_DELUGE: + if ((AI_DATA->atkAbility == ABILITY_VOLT_ABSORB + || AI_DATA->atkAbility == ABILITY_MOTOR_DRIVE + || AI_DATA->atkAbility == ABILITY_LIGHTNING_ROD) + && gBattleMoves[predictedMove].type == TYPE_NORMAL) + score += 2; + break; + case EFFECT_FLING: + /* TODO + switch (gFlingTable[AI_DATA->atkItem].effect) + { + case MOVE_EFFECT_BURN: + IncreaseBurnScore(battlerAtk, battlerDef, move, &score); + break; + case MOVE_EFFECT_FLINCH: + score += ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, 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)) + score += 3; + break; + }*/ + break; + case EFFECT_FEINT: + if (gBattleMoves[predictedMove].effect == EFFECT_PROTECT) + score += 3; + break; + case EFFECT_EMBARGO: + if (AI_DATA->defHoldEffect != HOLD_EFFECT_NONE) + score++; + break; + case EFFECT_POWDER: + if (predictedMove != MOVE_NONE && !IS_MOVE_STATUS(predictedMove) && gBattleMoves[predictedMove].type == TYPE_FIRE) + score += 3; + break; + case EFFECT_TELEKINESIS: + if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect) + || !IsBattlerGrounded(battlerDef)) + score++; + break; + case EFFECT_THROAT_CHOP: + if (predictedMove != MOVE_NONE && TestMoveFlags(predictedMove, FLAG_SOUND) && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) + score += 3; // Ai goes first and predicts the target will use a sound move + else if (TestMoveFlagsInMoveset(battlerDef, FLAG_SOUND)) + score += 3; + break; + case EFFECT_HEAL_BLOCK: + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && predictedMove != MOVE_NONE && IsHealingMoveEffect(gBattleMoves[predictedMove].effect)) + score += 3; // Try to cancel healing move + else if (HasHealingEffect(battlerDef) || AI_DATA->defHoldEffect == HOLD_EFFECT_LEFTOVERS + || (AI_DATA->defHoldEffect == HOLD_EFFECT_BLACK_SLUDGE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON))) + score += 2; + break; + case EFFECT_SOAK: + if (HasMoveWithType(battlerAtk, TYPE_ELECTRIC) || HasMoveWithType(battlerAtk, TYPE_GRASS) || HasMoveEffect(battlerAtk, EFFECT_FREEZE_DRY)) + score += 2; // Get some super effective moves + break; + case EFFECT_THIRD_TYPE: + if (AI_DATA->defAbility == ABILITY_WONDER_GUARD) + score += 2; // Give target more weaknesses + break; + case EFFECT_ELECTRIFY: + if (predictedMove != MOVE_NONE && gBattleMoves[predictedMove].type == TYPE_NORMAL + && (AI_DATA->atkAbility == ABILITY_VOLT_ABSORB + || AI_DATA->atkAbility == ABILITY_MOTOR_DRIVE + || AI_DATA->atkAbility == ABILITY_LIGHTNING_ROD)) + { + score += 3; + } + break; + case EFFECT_TOPSY_TURVY: + if (CountPositiveStatStages(battlerDef) > CountNegativeStatStages(battlerDef)) + score++; + break; + case EFFECT_FAIRY_LOCK: + if (!IsBattlerTrapped(battlerDef, TRUE)) + { + if (ShouldTrap(battlerAtk, battlerDef, move)) + score += 8; + } + break; + case EFFECT_QUASH: + if (isDoubleBattle + && GetWhoStrikesFirst(AI_DATA->battlerAtkPartner, battlerDef, TRUE) == 1) // Attacker partner wouldn't go before target + score++; + break; + case EFFECT_TAILWIND: + if (GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) + score += 2; + break; + case EFFECT_LUCKY_CHANT: + if (!isDoubleBattle) + { + score++; + } + else + { + if (CountUsablePartyMons(battlerDef) > 0) + score += 8; + } + 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 (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first + { + if (gBattleMoves[predictedMove].type == TYPE_GROUND) + score += 3; // Cause the enemy's move to fail + break; + } + else // Opponent Goes First + { + if (HasDamagingMoveOfType(battlerDef, TYPE_GROUND)) + score += 2; + break; + } + } + break; + case EFFECT_CAMOUFLAGE: + if (predictedMove != MOVE_NONE && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 // Attacker goes first + && !IS_MOVE_STATUS(move) && AI_GetTypeEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0) + score++; + break; + case EFFECT_FLAME_BURST: + if (isDoubleBattle) + { + if (IsBattlerAlive(AI_DATA->battlerDefPartner) + && GetHealthPercentage(AI_DATA->battlerDefPartner) < 12 + && AI_DATA->defPartnerAbility != ABILITY_MAGIC_GUARD + && !IS_BATTLER_OF_TYPE(AI_DATA->battlerDefPartner, TYPE_FIRE)) + score++; + } + break; + case EFFECT_TOXIC_THREAD: + IncreasePoisonScore(battlerAtk, battlerDef, move, &score); + IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score); + break; + case EFFECT_TWO_TURNS_ATTACK: + case EFFECT_SKULL_BASH: + case EFFECT_SOLARBEAM: + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_POWER_HERB) + score += 2; + break; + case EFFECT_COUNTER: + if (!IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) && predictedMove != MOVE_NONE) + { + if (gDisableStructs[battlerDef].tauntTimer != 0) + score++; // target must use damaging move + if (GetMoveDamageResult(predictedMove) >= MOVE_POWER_GOOD && GetBattleMoveSplit(predictedMove) == SPLIT_PHYSICAL) + score += 3; + } + break; + case EFFECT_MIRROR_COAT: + if (!IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) && predictedMove != MOVE_NONE) + { + if (gDisableStructs[battlerDef].tauntTimer != 0) + score++; // target must use damaging move + if (GetMoveDamageResult(predictedMove) >= MOVE_POWER_GOOD && GetBattleMoveSplit(predictedMove) == SPLIT_SPECIAL) + score += 3; + } + break; + case EFFECT_FLAIL: + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Ai goes first + { + if (GetHealthPercentage(battlerAtk) < 20) + score++; + else if (GetHealthPercentage(battlerAtk) < 8) + score += 2; + } + break; + case EFFECT_SHORE_UP: + if (AI_WeatherHasEffect() && (gBattleWeather & WEATHER_SANDSTORM_ANY) + && ShouldRecover(battlerAtk, battlerDef, move, 67)) + score += 3; + else if (ShouldRecover(battlerAtk, battlerDef, move, 50)) + score += 2; + break; + case EFFECT_FACADE: + if (gBattleMons[battlerAtk].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON)) + score++; + break; + case EFFECT_FOCUS_PUNCH: + if (!isDoubleBattle && effectiveness > AI_EFFECTIVENESS_x0_5) + { + if (IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility)) + score += 2; + else if (gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) + score++; + } + break; + case EFFECT_SMELLINGSALT: + if (gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS) + score += 2; + break; + case EFFECT_WAKE_UP_SLAP: + if (gBattleMons[battlerDef].status1 & STATUS1_SLEEP) + score += 2; + break; + case EFFECT_REVENGE: + if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP) + && !(gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION))) + score += 2; + break; + case EFFECT_ENDEAVOR: + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // Opponent faster + { + if (GetHealthPercentage(battlerAtk) < 40) + score++; + } + else if (GetHealthPercentage(battlerAtk) < 50) + { + score++; + } + break; + //case EFFECT_EXTREME_EVOBOOST: // TODO + //break; + //case EFFECT_CLANGOROUS_SOUL: // TODO + //break; + //case EFFECT_NO_RETREAT: // TODO + //break; + //case EFFECT_SKY_DROP + //break; + } // move effect checks - - - - } // move effect switch + return score; } -static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } -static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { } @@ -4867,7 +5946,7 @@ static void AI_Watch(void) AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); } -static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (IsBattlerTrapped(battlerAtk, FALSE)) return score; @@ -4876,7 +5955,7 @@ static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } -static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { u8 safariFleeRate = gBattleStruct->safariEscapeFactor * 5; // Safari flee rate, from 0-20. @@ -4888,7 +5967,7 @@ static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } -static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (GetHealthPercentage(battlerDef) <= 20) AI_Flee(); diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 34a42b6237..9002eaefe8 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -417,7 +417,7 @@ static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent) return FALSE; } -static bool8 ShouldSwitch(void) +bool32 ShouldSwitch(void) { u8 battlerIn1, battlerIn2; s32 firstId; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index fa8f38ea29..485d179fe4 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -4,6 +4,7 @@ #include "battle_anim.h" #include "battle_ai_util.h" #include "battle_ai_script_commands.h" +#include "battle_ai_switch_items.h" #include "battle_factory.h" #include "battle_setup.h" #include "data.h" @@ -17,8 +18,337 @@ #include "constants/battle_move_effects.h" #include "constants/hold_effects.h" #include "constants/moves.h" +#include "constants/items.h" // Const Data +static const s8 sAiAbilityRatings[ABILITIES_COUNT] = +{ + [ABILITY_ADAPTABILITY] = 8, + [ABILITY_AFTERMATH] = 5, + [ABILITY_AERILATE] = 8, + [ABILITY_AIR_LOCK] = 5, + [ABILITY_ANALYTIC] = 5, + [ABILITY_ANGER_POINT] = 4, + [ABILITY_ANTICIPATION] = 2, + [ABILITY_ARENA_TRAP] = 9, + [ABILITY_AROMA_VEIL] = 3, + [ABILITY_AURA_BREAK] = 3, + [ABILITY_BAD_DREAMS] = 4, + [ABILITY_BATTERY] = 0, + [ABILITY_BATTLE_ARMOR] = 2, + [ABILITY_BATTLE_BOND] = 6, + [ABILITY_BEAST_BOOST] = 7, + [ABILITY_BERSERK] = 5, + [ABILITY_BIG_PECKS] = 1, + [ABILITY_BLAZE] = 5, + [ABILITY_BULLETPROOF] = 7, + [ABILITY_CHEEK_POUCH] = 4, + [ABILITY_CHLOROPHYLL] = 6, + [ABILITY_CLEAR_BODY] = 4, + [ABILITY_CLOUD_NINE] = 5, + [ABILITY_COLOR_CHANGE] = 2, + [ABILITY_COMATOSE] = 6, + [ABILITY_COMPETITIVE] = 5, + [ABILITY_COMPOUND_EYES] = 7, + [ABILITY_CONTRARY] = 8, + [ABILITY_CORROSION] = 5, + [ABILITY_CURSED_BODY] = 4, + [ABILITY_CUTE_CHARM] = 2, + [ABILITY_DAMP] = 2, + [ABILITY_DANCER] = 5, + [ABILITY_DARK_AURA] = 6, + [ABILITY_DAZZLING] = 5, + [ABILITY_DEFEATIST] = -1, + [ABILITY_DEFIANT] = 5, + [ABILITY_DELTA_STREAM] = 10, + [ABILITY_DESOLATE_LAND] = 10, + [ABILITY_DISGUISE] = 8, + [ABILITY_DOWNLOAD] = 7, + [ABILITY_DRIZZLE] = 9, + [ABILITY_DROUGHT] = 9, + [ABILITY_DRY_SKIN] = 6, + [ABILITY_EARLY_BIRD] = 4, + [ABILITY_EFFECT_SPORE] = 4, + [ABILITY_ELECTRIC_SURGE] = 8, + [ABILITY_EMERGENCY_EXIT] = 3, + [ABILITY_FAIRY_AURA] = 6, + [ABILITY_FILTER] = 6, + [ABILITY_FLAME_BODY] = 4, + [ABILITY_FLARE_BOOST] = 5, + [ABILITY_FLASH_FIRE] = 6, + [ABILITY_FLOWER_GIFT] = 4, + [ABILITY_FLOWER_VEIL] = 0, + [ABILITY_FLUFFY] = 5, + [ABILITY_FORECAST] = 6, + [ABILITY_FOREWARN] = 2, + [ABILITY_FRIEND_GUARD] = 0, + [ABILITY_FRISK] = 3, + [ABILITY_FULL_METAL_BODY] = 4, + [ABILITY_FUR_COAT] = 7, + [ABILITY_GALE_WINGS] = 6, + [ABILITY_GALVANIZE] = 8, + [ABILITY_GLUTTONY] = 3, + [ABILITY_GOOEY] = 5, + [ABILITY_GRASS_PELT] = 2, + [ABILITY_GRASSY_SURGE] = 8, + [ABILITY_GUTS] = 6, + [ABILITY_HARVEST] = 5, + [ABILITY_HEALER] = 0, + [ABILITY_HEATPROOF] = 5, + [ABILITY_HEAVY_METAL] = -1, + [ABILITY_HONEY_GATHER] = 0, + [ABILITY_HUGE_POWER] = 10, + [ABILITY_HUSTLE] = 7, + [ABILITY_HYDRATION] = 4, + [ABILITY_HYPER_CUTTER] = 3, + [ABILITY_ICE_BODY] = 3, + [ABILITY_ILLUMINATE] = 0, + [ABILITY_ILLUSION] = 8, + [ABILITY_IMMUNITY] = 4, + [ABILITY_IMPOSTER] = 9, + [ABILITY_INFILTRATOR] = 6, + [ABILITY_INNARDS_OUT] = 5, + [ABILITY_INNER_FOCUS] = 2, + [ABILITY_INSOMNIA] = 4, + [ABILITY_INTIMIDATE] = 7, + [ABILITY_IRON_BARBS] = 6, + [ABILITY_IRON_FIST] = 6, + [ABILITY_JUSTIFIED] = 4, + [ABILITY_KEEN_EYE] = 1, + [ABILITY_KLUTZ] = -1, + [ABILITY_LEAF_GUARD] = 2, + [ABILITY_LEVITATE] = 7, + [ABILITY_LIGHT_METAL] = 2, + [ABILITY_LIGHTNING_ROD] = 7, + [ABILITY_LIMBER] = 3, + [ABILITY_LIQUID_OOZE] = 3, + [ABILITY_LIQUID_VOICE] = 5, + [ABILITY_LONG_REACH] = 3, + [ABILITY_MAGIC_BOUNCE] = 9, + [ABILITY_MAGIC_GUARD] = 9, + [ABILITY_MAGICIAN] = 3, + [ABILITY_MAGMA_ARMOR] = 1, + [ABILITY_MAGNET_PULL] = 9, + [ABILITY_MARVEL_SCALE] = 5, + [ABILITY_MEGA_LAUNCHER] = 7, + [ABILITY_MERCILESS] = 4, + [ABILITY_MINUS] = 0, + [ABILITY_MISTY_SURGE] = 8, + [ABILITY_MOLD_BREAKER] = 7, + [ABILITY_MOODY] = 10, + [ABILITY_MOTOR_DRIVE] = 6, + [ABILITY_MOXIE] = 7, + [ABILITY_MULTISCALE] = 8, + [ABILITY_MULTITYPE] = 8, + [ABILITY_MUMMY] = 5, + [ABILITY_NATURAL_CURE] = 7, + [ABILITY_NEUROFORCE] = 6, + [ABILITY_NO_GUARD] = 8, + [ABILITY_NORMALIZE] = -1, + [ABILITY_OBLIVIOUS] = 2, + [ABILITY_OVERCOAT] = 5, + [ABILITY_OVERGROW] = 5, + [ABILITY_OWN_TEMPO] = 3, + [ABILITY_PARENTAL_BOND] = 10, + [ABILITY_PICKUP] = 1, + [ABILITY_PICKPOCKET] = 3, + [ABILITY_PIXILATE] = 8, + [ABILITY_PLUS] = 0, + [ABILITY_POISON_HEAL] = 8, + [ABILITY_POISON_POINT] = 4, + [ABILITY_POISON_TOUCH] = 4, + //[ABILITY_PORTAL_POWER] = 8, + [ABILITY_POWER_CONSTRUCT] = 10, + [ABILITY_POWER_OF_ALCHEMY] = 0, + [ABILITY_PRANKSTER] = 8, + [ABILITY_PRESSURE] = 5, + [ABILITY_PRIMORDIAL_SEA] = 10, + [ABILITY_PRISM_ARMOR] = 6, + [ABILITY_PROTEAN] = 8, + [ABILITY_PSYCHIC_SURGE] = 8, + [ABILITY_PURE_POWER] = 10, + [ABILITY_QUEENLY_MAJESTY] = 6, + [ABILITY_QUICK_FEET] = 5, + [ABILITY_RAIN_DISH] = 3, + [ABILITY_RATTLED] = 3, + [ABILITY_RECEIVER] = 0, + [ABILITY_RECKLESS] = 6, + [ABILITY_REFRIGERATE] = 8, + [ABILITY_REGENERATOR] = 8, + [ABILITY_RIVALRY] = 1, + [ABILITY_RKS_SYSTEM] = 8, + [ABILITY_ROCK_HEAD] = 5, + [ABILITY_ROUGH_SKIN] = 6, + [ABILITY_RUN_AWAY] = 0, + [ABILITY_SAND_FORCE] = 4, + [ABILITY_SAND_RUSH] = 6, + [ABILITY_SAND_STREAM] = 9, + [ABILITY_SAND_VEIL] = 3, + [ABILITY_SAP_SIPPER] = 7, + [ABILITY_SCHOOLING] = 6, + [ABILITY_SCRAPPY] = 6, + [ABILITY_SERENE_GRACE] = 8, + [ABILITY_SHADOW_SHIELD] = 8, + [ABILITY_SHADOW_TAG] = 10, + [ABILITY_SHED_SKIN] = 7, + [ABILITY_SHEER_FORCE] = 8, + [ABILITY_SHELL_ARMOR] = 2, + [ABILITY_SHIELD_DUST] = 5, + [ABILITY_SHIELDS_DOWN] = 6, + [ABILITY_SIMPLE] = 8, + [ABILITY_SKILL_LINK] = 7, + [ABILITY_SLOW_START] = -2, + [ABILITY_SLUSH_RUSH] = 5, + [ABILITY_SNIPER] = 3, + [ABILITY_SNOW_CLOAK] = 3, + [ABILITY_SNOW_WARNING] = 8, + [ABILITY_SOLAR_POWER] = 3, + [ABILITY_SOLID_ROCK] = 6, + [ABILITY_SOUL_HEART] = 7, + [ABILITY_SOUNDPROOF] = 4, + [ABILITY_SPEED_BOOST] = 9, + [ABILITY_STAKEOUT] = 6, + [ABILITY_STALL] = -1, + [ABILITY_STAMINA] = 6, + [ABILITY_STANCE_CHANGE] = 10, + [ABILITY_STATIC] = 4, + [ABILITY_STEADFAST] = 2, + [ABILITY_STEELWORKER] = 6, + [ABILITY_STENCH] = 1, + [ABILITY_STICKY_HOLD] = 3, + [ABILITY_STORM_DRAIN] = 7, + [ABILITY_STRONG_JAW] = 6, + [ABILITY_STURDY] = 6, + [ABILITY_SUCTION_CUPS] = 2, + [ABILITY_SUPER_LUCK] = 3, + [ABILITY_SURGE_SURFER] = 4, + [ABILITY_SWARM] = 5, + [ABILITY_SWEET_VEIL] = 4, + [ABILITY_SWIFT_SWIM] = 6, + [ABILITY_SYMBIOSIS] = 0, + [ABILITY_SYNCHRONIZE] = 4, + [ABILITY_TANGLED_FEET] = 2, + [ABILITY_TANGLING_HAIR] = 5, + [ABILITY_TECHNICIAN] = 8, + [ABILITY_TELEPATHY] = 0, + [ABILITY_TERAVOLT] = 7, + [ABILITY_THICK_FAT] = 7, + [ABILITY_TINTED_LENS] = 7, + [ABILITY_TORRENT] = 5, + [ABILITY_TOXIC_BOOST] = 6, + [ABILITY_TOUGH_CLAWS] = 7, + [ABILITY_TRACE] = 6, + [ABILITY_TRIAGE] = 7, + [ABILITY_TRUANT] = -2, + [ABILITY_TURBOBLAZE] = 7, + [ABILITY_UNAWARE] = 6, + [ABILITY_UNBURDEN] = 7, + [ABILITY_UNNERVE] = 3, + [ABILITY_VICTORY_STAR] = 6, + [ABILITY_VITAL_SPIRIT] = 4, + [ABILITY_VOLT_ABSORB] = 7, + [ABILITY_WATER_ABSORB] = 7, + [ABILITY_WATER_BUBBLE] = 8, + [ABILITY_WATER_COMPACTION] = 4, + [ABILITY_WATER_VEIL] = 4, + [ABILITY_WEAK_ARMOR] = 2, + [ABILITY_WHITE_SMOKE] = 4, + [ABILITY_WIMP_OUT] = 3, + [ABILITY_WONDER_GUARD] = 10, + [ABILITY_WONDER_SKIN] = 4, + [ABILITY_ZEN_MODE] = -1, + [ABILITY_INTREPID_SWORD] = 3, + [ABILITY_DAUNTLESS_SHIELD] = 3, + [ABILITY_BALL_FETCH] = 0, + [ABILITY_COTTON_DOWN] = 3, + [ABILITY_MIRROR_ARMOR] = 6, + [ABILITY_GULP_MISSILE] = 3, + [ABILITY_STALWART] = 2, + [ABILITY_PROPELLER_TAIL] = 2, + [ABILITY_STEAM_ENGINE] = 3, + [ABILITY_PUNK_ROCK] = 2, + [ABILITY_SAND_SPIT] = 5, + [ABILITY_ICE_SCALES] = 7, + [ABILITY_RIPEN] = 4, + [ABILITY_ICE_FACE] = 4, + [ABILITY_POWER_SPOT] = 2, + [ABILITY_MIMICRY] = 2, + [ABILITY_SCREEN_CLEANER] = 3, + [ABILITY_NEUTRALIZING_GAS] = 5, + [ABILITY_HUNGER_SWITCH] = 2, + [ABILITY_PASTEL_VEIL] = 4, + [ABILITY_STEELY_SPIRIT] = 2, + [ABILITY_PERISH_BODY] = -1, + [ABILITY_WANDERING_SPIRIT] = 2, + [ABILITY_GORILLA_TACTICS] = 4, +}; + +static const u16 sEncouragedEncoreEffects[] = +{ + EFFECT_DREAM_EATER, + EFFECT_ATTACK_UP, + EFFECT_DEFENSE_UP, + EFFECT_SPEED_UP, + EFFECT_SPECIAL_ATTACK_UP, + EFFECT_HAZE, + EFFECT_ROAR, + EFFECT_CONVERSION, + EFFECT_TOXIC, + EFFECT_LIGHT_SCREEN, + EFFECT_REST, + EFFECT_SUPER_FANG, + EFFECT_SPECIAL_DEFENSE_UP_2, + EFFECT_CONFUSE, + EFFECT_POISON, + EFFECT_PARALYZE, + EFFECT_LEECH_SEED, + EFFECT_DO_NOTHING, + EFFECT_ATTACK_UP_2, + EFFECT_ENCORE, + EFFECT_CONVERSION_2, + EFFECT_LOCK_ON, + EFFECT_HEAL_BELL, + EFFECT_MEAN_LOOK, + EFFECT_NIGHTMARE, + EFFECT_PROTECT, + EFFECT_SKILL_SWAP, + EFFECT_FORESIGHT, + EFFECT_PERISH_SONG, + EFFECT_SANDSTORM, + EFFECT_ENDURE, + EFFECT_SWAGGER, + EFFECT_ATTRACT, + EFFECT_SAFEGUARD, + EFFECT_RAIN_DANCE, + EFFECT_SUNNY_DAY, + EFFECT_BELLY_DRUM, + EFFECT_PSYCH_UP, + EFFECT_FUTURE_SIGHT, + EFFECT_FAKE_OUT, + EFFECT_STOCKPILE, + EFFECT_SPIT_UP, + EFFECT_SWALLOW, + EFFECT_HAIL, + EFFECT_TORMENT, + EFFECT_WILL_O_WISP, + EFFECT_FOLLOW_ME, + EFFECT_CHARGE, + EFFECT_TRICK, + EFFECT_ROLE_PLAY, + EFFECT_INGRAIN, + EFFECT_RECYCLE, + EFFECT_KNOCK_OFF, + EFFECT_SKILL_SWAP, + EFFECT_IMPRISON, + EFFECT_REFRESH, + EFFECT_GRUDGE, + EFFECT_TEETER_DANCE, + EFFECT_MUD_SPORT, + EFFECT_WATER_SPORT, + EFFECT_DRAGON_DANCE, + EFFECT_CAMOUFLAGE, +}; + static const u16 sDiscouragedPowerfulMoveEffects[] = { EFFECT_EXPLOSION, @@ -242,7 +572,14 @@ void RestoreBattlerData(u8 battlerId) u32 GetHealthPercentage(u8 battlerId) { return (u32)((100 * gBattleMons[battlerId].hp) / gBattleMons[battlerId].maxHP); -} +} + +bool32 AtMaxHp(u8 battlerId) +{ + if (GetHealthPercentage(battlerId) == 100) + return TRUE; + return FALSE; +} bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch) { @@ -267,6 +604,15 @@ bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch) } // move checks +bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect) +{ + if ((B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) + || ability == ABILITY_OVERCOAT + || GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_SAFETY_GOOGLES) + 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 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split) @@ -543,7 +889,7 @@ u8 AI_GetMoveEffectiveness(u16 move) // AI_CHECK_FASTER: is user(ai) faster // AI_CHECK_SLOWER: is target faster -bool32 IsBattlerFaster(u8 battler) +bool32 IsAiFaster(u8 battler) { u32 fasterAI = 0, fasterPlayer = 0, i; s8 prioAI, prioPlayer; @@ -608,6 +954,17 @@ bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk) return FALSE; } +bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits) +{ + s32 i, dmg; + u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP); + + if (move != MOVE_NONE && move != 0xFFFF && !(unusable & gBitTable[i]) && AI_CalcDamage(move, battlerDef, battlerAtk) >= gBattleMons[battlerAtk].hp) + return TRUE; + + return FALSE; +} + // Check if target has means to faint ai mon after modding hp/dmg bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod) { @@ -617,8 +974,11 @@ bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgM for (i = 0; i < MAX_MON_MOVES; i++) { - u32 dmg = AI_CalcDamage(moves[i], battlerDef, battlerAtk) + dmgMod; + u32 dmg = AI_CalcDamage(moves[i], battlerDef, battlerAtk); u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod; + if (dmgMod) + dmg *= dmgMod; + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i]) && dmg >= hpCheck) { return TRUE; @@ -950,7 +1310,7 @@ bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbilit gPotentialItemEffectBattler = battlerDef; if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < GetBattlerHoldEffectParam(battlerDef)) return FALSE; //probabilistically speaking, focus band should activate so dont OHKO - else if (holdEffect == HOLD_EFFECT_FOCUS_SASH && GetHealthPercentage(battlerDef) == 100) + else if (holdEffect == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef)) return FALSE; if (!DoesBattlerIgnoreAbilityChecks(atkAbility, move) && defAbility == ABILITY_STURDY) @@ -972,6 +1332,147 @@ bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbilit return FALSE; } +bool32 ShouldSetSandstorm(u8 battler, u16 ability, u16 holdEffect) +{ + if (!AI_WeatherHasEffect()) + return FALSE; + else if (gBattleWeather & WEATHER_SANDSTORM_ANY) + return FALSE; + + if (ability == ABILITY_SAND_VEIL + || ability == ABILITY_SAND_RUSH + || ability == ABILITY_SAND_FORCE + || ability == ABILITY_SAND_FORCE + || ability == ABILITY_OVERCOAT + || ability == ABILITY_MAGIC_GUARD + || holdEffect == HOLD_EFFECT_SAFETY_GOOGLES + || 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(u8 battler, u16 ability, u16 holdEffect) +{ + if (!AI_WeatherHasEffect()) + return FALSE; + else if (gBattleWeather & WEATHER_HAIL_ANY) + 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_GOOGLES + || IS_BATTLER_OF_TYPE(battler, TYPE_ICE) + || HasMove(battler, MOVE_BLIZZARD) + || HasMoveEffect(battler, EFFECT_AURORA_VEIL) + || HasMoveEffect(battler, EFFECT_WEATHER_BALL)) + { + return TRUE; + } + return FALSE; +} + +bool32 ShouldSetRain(u8 battlerAtk, u16 atkAbility, u16 holdEffect) +{ + if (!AI_WeatherHasEffect()) + return FALSE; + else if (gBattleWeather & WEATHER_RAIN_ANY) + 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_HURRICANE) + || HasMoveEffect(battlerAtk, EFFECT_WEATHER_BALL) + || HasMoveWithType(battlerAtk, TYPE_WATER))) + { + return TRUE; + } + return FALSE; +} + +bool32 ShouldSetSun(u8 battlerAtk, u16 atkAbility, u16 holdEffect) +{ + if (!AI_WeatherHasEffect()) + return FALSE; + else if (gBattleWeather & WEATHER_SUN_ANY) + 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_SOLARBEAM) + || 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; +} + + +void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s16 *score) +{ + // TODO more sophisticated logic + u16 predictedEffect = gBattleMoves[predictedMove].effect; + u8 defAbility = AI_GetAbility(battlerDef); + u32 uses = gDisableStructs[battlerAtk].protectUses; + + /*if (GetMoveResultFlags(predictedMove) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) + { + (*score) -= 5; + return; + }*/ + + if (uses == 0) + { + if (predictedMove != MOVE_NONE && predictedMove != 0xFFFF && !IS_MOVE_STATUS(predictedMove)) + (*score) += 2; + else if (Random() % 256 < 100) + (*score)++; + } + else + { + if (IsDoubleBattle()) + (*score) -= 2 * min(uses, 3); + else + (*score) -= min(uses, 3); + } + + if (gBattleMons[battlerAtk].status1 & (STATUS1_PSN_ANY | STATUS1_BURN) + || gBattleMons[battlerAtk].status2 & (STATUS2_CURSED | STATUS2_INFATUATION) + || gStatuses3[battlerAtk] & (STATUS3_PERISH_SONG | STATUS3_LEECHSEED | STATUS3_YAWN)) + { + (*score)--; + } + + if (gBattleMons[battlerDef].status1 & STATUS1_TOXIC_POISON + || gBattleMons[battlerDef].status2 & (STATUS2_CURSED | STATUS2_INFATUATION) + || gStatuses3[battlerDef] & (STATUS3_PERISH_SONG | STATUS3_LEECHSEED | STATUS3_YAWN)) + (*score) += 2; +} + // stat stages bool32 BattlerStatCanFall(u8 battler, u16 battlerAbility, u8 stat) { @@ -1050,23 +1551,115 @@ bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability) bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) { - if (IsBattlerFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex)) - return FALSE; //Don't bother lowering stats if can kill enemy. + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. - if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4 && HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL) + if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4 + && HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL) && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_WHITE_SMOKE - //&& defAbility != ABILITY_FULLMETALBODY + //&& defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_HYPER_CUTTER) return TRUE; return FALSE; } -bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index) +bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +{ + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 + && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + && defAbility != ABILITY_WHITE_SMOKE + //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_BIG_PECKS) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +{ + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (IsAiFaster(AI_CHECK_SLOWER) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_WHITE_SMOKE) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +{ + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4 + && HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_WHITE_SMOKE) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +{ + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + return FALSE; // Don't bother lowering stats if can kill enemy. + + if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4 + && HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) + && defAbility != ABILITY_CONTRARY + && defAbility != ABILITY_CLEAR_BODY + //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_WHITE_SMOKE) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +{ + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 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) + return TRUE; + return FALSE; +} + +bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +{ + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 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) + return TRUE; + return FALSE; +} + +bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits) { s32 dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][index]; + if (numHits) + dmg *= numHits; + if (gBattleMons[battlerDef].hp <= dmg) return TRUE; return FALSE; @@ -1122,7 +1715,21 @@ bool32 HasMoveEffect(u32 battlerId, u16 moveEffect) return FALSE; } -bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 ignoreStatus, u16 atkAbility, u16 defAbility, u16 atkHoldEffect, u16 defHoldEffect, u16 move) +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] != 0xFFFF && moves[i] == move) + return TRUE; + } + + return FALSE; +} + +bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 ignoreStatus, u16 atkAbility, u16 defAbility, u16 atkHoldEffect, u16 defHoldEffect) { s32 i; u16 *moves = GetMovesArray(battlerAtk); @@ -1137,11 +1744,11 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 { if (ignoreStatus && IS_MOVE_STATUS(moves[i])) continue; - else if ((!IS_MOVE_STATUS(moves[i]) && gBattleMoves[move].accuracy == 0) - || gBattleMoves[move].target & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) + else if ((!IS_MOVE_STATUS(moves[i]) && gBattleMoves[moves[i]].accuracy == 0) + || gBattleMoves[moves[i]].target & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) continue; - if (AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, move) <= accCheck) + if (AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, moves[i]) <= accCheck) return TRUE; } } @@ -1149,6 +1756,123 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 return FALSE; } +bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef) +{ + u8 moveLimitations = CheckMoveLimitations(battlerAtk, 0, 0xFF); + 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 (gBattleMoves[moves[i]].effect == EFFECT_SLEEP + && AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, moves[i]) < 85) + return TRUE; + } + } + return FALSE; +} + +bool32 IsHealingMoveEffect(u16 effect) +{ + switch (effect) + { + case EFFECT_RESTORE_HP: + case EFFECT_MORNING_SUN: + case EFFECT_SYNTHESIS: + case EFFECT_MOONLIGHT: + case EFFECT_SOFTBOILED: + case EFFECT_ROOST: + case EFFECT_SWALLOW: + case EFFECT_WISH: + case EFFECT_HEALING_WISH: + case EFFECT_HEAL_PULSE: + case EFFECT_REST: + return TRUE; + default: + return FALSE; + } +} + +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] != 0xFFFF && IsHealingMoveEffect(gBattleMoves[moves[i]].effect)) + return TRUE; + } + + return FALSE; +} + +bool32 IsThawingMove(u16 move) +{ + switch (move) + { + case MOVE_FLAME_WHEEL: + case MOVE_SACRED_FIRE: + case MOVE_FLARE_BLITZ: + case MOVE_SCALD: + case MOVE_SCORCHING_SANDS: + case MOVE_FUSION_FLARE: + case MOVE_STEAM_ERUPTION: + case MOVE_BURN_UP: + case MOVE_PYRO_BALL: + return TRUE; + default: + return FALSE; + } +} + +bool32 HasThawingMove(u8 battlerId) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && IsThawingMove(moves[i])) + return TRUE; + } + + return FALSE; +} + +bool32 HasDamagingMove(u8 battlerId) +{ + u32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && gBattleMoves[moves[i]].power != 0) + return TRUE; + } + + return FALSE; +} + +bool32 HasDamagingMoveOfType(u8 battlerId, u8 type) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF + && gBattleMoves[moves[i]].type == type && gBattleMoves[moves[i]].power != 0) + return TRUE; + } + + return FALSE; +} + bool32 IsInstructBannedMove(u16 move) { u32 i; @@ -1160,6 +1884,18 @@ bool32 IsInstructBannedMove(u16 move) return FALSE; } +bool32 IsEncoreEncouragedEffect(u16 moveEffect) +{ + u32 i; + + for (i = 0; i < ARRAY_COUNT(sEncouragedEncoreEffects); i++) + { + if (moveEffect == sEncouragedEncoreEffects[i]) + return TRUE; + } + return FALSE; +} + bool32 MoveRequiresRecharging(u16 move) { u32 i; @@ -1195,20 +1931,6 @@ bool32 TestMoveFlagsInMoveset(u8 battler, u32 flags) return FALSE; } -bool32 BattlerHasDamagingMove(u8 battlerId) -{ - u32 i; - u16 *moves = GetMovesArray(battlerId); - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && gBattleMoves[moves[i]].power != 0) - return TRUE; - } - - return FALSE; -} - static u32 GetLeechSeedDamage(u8 battlerId) { u32 damage = 0; @@ -1345,7 +2067,7 @@ static u32 GetWeatherDamage(u8 battlerId) return damage; } -bool32 BattlerHasSecondaryDamage(u8 battlerId) +u32 GetBattlerSecondaryDamage(u8 battlerId) { u32 secondaryDamage; @@ -1359,9 +2081,7 @@ bool32 BattlerHasSecondaryDamage(u8 battlerId) + GetPoisonDamage(battlerId) + GetWeatherDamage(battlerId); - if (secondaryDamage != 0) - return TRUE; - return FALSE; + return secondaryDamage; } bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability) @@ -1373,26 +2093,327 @@ bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability) return FALSE; } +bool32 BattlerWillFaintFromSecondaryDamage(u8 battler, u16 ability) +{ + if (GetBattlerSecondaryDamage(battler) != 0 + && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 16) + return TRUE; + return FALSE; +} + +static bool32 AnyUsefulStatIsRaised(u8 battler) +{ + u8 statId; + + for (statId = STAT_ATK; statId < NUM_BATTLE_STATS; statId++) + { + if (gBattleMons[battler].statStages[statId] > DEFAULT_STAT_STAGE) + { + switch (statId) + { + case STAT_ATK: + if (HasMoveWithSplit(battler, SPLIT_PHYSICAL)) + return TRUE; + break; + case STAT_SPATK: + if (HasMoveWithSplit(battler, SPLIT_SPECIAL)) + return TRUE; + break; + case STAT_SPEED: + return TRUE; + } + } + } + + return FALSE; +} + +static bool32 PartyBattlerShouldAvoidHazards(u8 currBattler, u8 switchBattler) +{ + struct Pokemon *mon = GetBattlerPartyData(switchBattler); + u16 ability = GetMonAbility(mon); // we know our own party data + u16 holdEffect = GetBattlerHoldEffect(GetMonData(mon, MON_DATA_HELD_ITEM), TRUE); + u32 flags = gSideStatuses[GetBattlerSide(currBattler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES); + + if (flags == 0) + return FALSE; + + if (ability == ABILITY_MAGIC_GUARD || ability == ABILITY_LEVITATE + || holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS) + return FALSE; + + if (flags & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK) && GetMonData(mon, MON_DATA_HP) < (GetMonData(mon, MON_DATA_MAX_HP) / 8)) + return TRUE; + + return FALSE; +} + +enum { + DONT_PIVOT, + CAN_TRY_PIVOT, + PIVOT, +}; +bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 moveIndex) +{ + bool8 hasStatBoost = AnyUsefulStatIsRaised(battlerAtk) || gBattleMons[battlerDef].statStages[STAT_EVASION] >= 9; //Significant boost in evasion for any class + u8 backupBattler = gActiveBattler; + bool32 shouldSwitch; + u8 battlerToSwitch; + + gActiveBattler = battlerAtk; + shouldSwitch = ShouldSwitch(); + battlerToSwitch = *(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler); + gActiveBattler = backupBattler; + + 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 (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first + { + if (!CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) // Can't KO foe otherwise + { + if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 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->defHoldEffect == HOLD_EFFECT_FOCUS_SASH + || 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->defHoldEffect == HOLD_EFFECT_FOCUS_SASH + || 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->atkAbility) && switchScore >= SWITCHING_INCREASE_WALLS_FOE) + return PIVOT;*/ + + /*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE) + { + bool8 physMoveInMoveset = PhysicalMoveInMoveset(battlerAtk); + bool8 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 (gBattleMoves[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 (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + { + if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility)) + 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 (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + { + if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility) // This is the only move that can KO + && !hasStatBoost) //You're not wasting a valuable stat boost + { + return CAN_TRY_PIVOT; + } + } + else if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 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->defHoldEffect == 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) + { + bool8 physMoveInMoveset = PhysicalMoveInMoveset(battlerAtk); + bool8 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(u8 battler, u16 item) +{ + if (item == ITEM_NONE) + return FALSE; + + if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_SECRET_BASE + #if defined B_TRAINERS_KNOCK_OFF_ITEMS + | BATTLE_TYPE_TRAINER + #endif + )) && GetBattlerSide(battler) == B_SIDE_PLAYER) + return FALSE; + + if (AI_GetAbility(battler) == ABILITY_STICKY_HOLD) + return FALSE; + + if (!CanBattlerGetOrLoseItem(battler, item)) + return FALSE; + + return TRUE; +} + // status checks +bool32 IsBattlerIncapacitated(u8 battler, u16 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 CanSleep(u8 battler, u16 ability) +{ + if (ability == ABILITY_INSOMNIA + || ability == ABILITY_VITAL_SPIRIT + || 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(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { - if (defAbility == ABILITY_INSOMNIA - || defAbility == ABILITY_VITAL_SPIRIT - || gBattleMons[battlerDef].status1 & STATUS1_ANY - || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD - || IsAbilityStatusProtected(battlerDef) + if (!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; } +bool32 CanBePoisoned(u8 battler, u16 ability) +{ + if (ability == ABILITY_IMMUNITY + || ability == ABILITY_PASTEL_VEIL + || gBattleMons[battler].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battler) + || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) + return FALSE; + return TRUE; +} + +bool32 ShouldPoisonSelf(u8 battler, u16 ability) +{ + if (CanBePoisoned(battler, ability) && ( + ability == ABILITY_MARVEL_SCALE + || ability == ABILITY_POISON_HEAL + || ability == ABILITY_QUICK_FEET + || ability == ABILITY_MAGIC_GUARD + || (ability == ABILITY_TOXIC_BOOST && HasMoveWithSplit(battler, SPLIT_PHYSICAL)) + || (ability == ABILITY_GUTS && HasMoveWithSplit(battler, SPLIT_PHYSICAL)) + || HasMoveEffect(battler, EFFECT_FACADE) + || HasMoveEffect(battler, EFFECT_PSYCHO_SHIFT))) + return TRUE; + return FALSE; +} + bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { - if (defAbility == ABILITY_IMMUNITY - || defAbility == ABILITY_PASTEL_VEIL - || gBattleMons[battlerDef].status1 & STATUS1_ANY - || IsAbilityStatusProtected(battlerDef) + if (!CanBePoisoned(battlerDef, defAbility) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) return FALSE; @@ -1410,6 +2431,7 @@ bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u1 || IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC) || gBattleMons[battlerDef].status1 & STATUS1_ANY || IsAbilityStatusProtected(battlerDef) + || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) return FALSE; @@ -1421,6 +2443,7 @@ bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtk if ((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && defAbility == ABILITY_OWN_TEMPO) || (IsBattlerGrounded(battlerDef) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) { @@ -1430,13 +2453,35 @@ bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtk return TRUE; } +bool32 CanBeBurned(u8 battler, u16 ability) +{ + if (ability == ABILITY_WATER_VEIL + || ability == ABILITY_WATER_BUBBLE + || 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 ShouldBurnSelf(u8 battler, u16 ability) +{ + if (CanBeBurned(battler, ability) && ( + ability == ABILITY_QUICK_FEET + || ability == ABILITY_HEATPROOF + || ability == ABILITY_MAGIC_GUARD + || (ability == ABILITY_FLARE_BOOST && HasMoveWithSplit(battler, SPLIT_SPECIAL)) + || (ability == ABILITY_GUTS && HasMoveWithSplit(battler, SPLIT_PHYSICAL)) + || HasMoveEffect(battler, EFFECT_FACADE) + || HasMoveEffect(battler, EFFECT_PSYCHO_SHIFT))) + return TRUE; + return FALSE; +} + bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) { - if (defAbility == ABILITY_WATER_VEIL - || defAbility == ABILITY_WATER_BUBBLE - || IS_BATTLER_OF_TYPE(battlerDef, TYPE_FIRE) - || gBattleMons[battlerDef].status1 & STATUS1_ANY - || IsAbilityStatusProtected(battlerDef) + if (!CanBeBurned(battlerDef, defAbility) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove)) { @@ -1458,6 +2503,74 @@ bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGe return TRUE; } +u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move) +{ + if (defAbility == ABILITY_INNER_FOCUS + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) + { + return 0; // don't try to flinch + } + else if ((gBattleMons[battlerDef].status1 & STATUS1_SLEEP) && !HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK) && !HasMoveEffect(battlerDef, EFFECT_SNORE)) + { + return 0; // don't try to flinch sleeping pokemon + } + else if (atkAbility == ABILITY_SERENE_GRACE + || gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS + || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION + || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + { + return 2; // good idea to flinch + } + return 1; // decent idea to flinch +} + +bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move) +{ + if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->defAbility)) + return TRUE; // battler is taking secondary damage with low HP + + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL) + { + if (!CanTargetFaintAi(battlerDef, battlerAtk)) + return TRUE; // attacker goes first and opponent can't kill us + } + + return FALSE; +} + +bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move) +{ + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND && CountUsablePartyMons(battlerAtk) == 0) + return FALSE; // don't lock attacker into fake out if can't switch out + + if (gDisableStructs[battlerAtk].isFirstTurn + && ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, move) + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, move)) + return TRUE; + + return FALSE; +} + +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(u8 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(u8 battlerId, bool32 checkSoundproof) { @@ -1505,9 +2618,9 @@ u16 GetBattlerSideSpeedAverage(u8 battler) bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex) { if (recoilDmg >= gBattleMons[battlerAtk].hp //Recoil kills attacker - && CountUsablePartyMons(battlerDef) > 1) //Foe has more than 1 target left + && CountUsablePartyMons(battlerDef) != 0) //Foe has more than 1 target left { - if (recoilDmg >= gBattleMons[battlerDef].hp && !CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex)) + if (recoilDmg >= gBattleMons[battlerDef].hp && !CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 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 @@ -1516,14 +2629,17 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI return TRUE; } -bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) +bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) { - if (move == 0xFFFF || GetWhoStrikesFirst(sBattler_AI, gBattlerTarget, TRUE) == 0) + if (move == 0xFFFF || GetWhoStrikesFirst(battlerAtk, gBattlerTarget, TRUE) == 0) { // using item or user goes first u8 healPercent = (gBattleMoves[move].argument == 0) ? 50 : gBattleMoves[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 @@ -1540,6 +2656,66 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) return FALSE; } +bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent) +{ + if (move == 0xFFFF || GetWhoStrikesFirst(battlerAtk, gBattlerTarget, TRUE) == 0) + { + // using item or user going first + s32 damage = AI_THINKING_STRUCT->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) && GetHealthPercentage(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(u8 battlerAtk, u8 battlerDef, u16 moveEffect) +{ + u8 atkSide = GetBattlerSide(battlerAtk); + + if (gSideTimers[atkSide].auroraVeilTimer != 0) + { + bool8 defHasPhysical = HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL); + bool8 defHasSpecial = HasMoveWithSplit(battlerDef, SPLIT_SPECIAL); + + switch (moveEffect) + { + case EFFECT_AURORA_VEIL: + if (gBattleWeather & WEATHER_HAIL_ANY + && !((gSideStatuses[atkSide] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN)))) + return TRUE; + break; + case EFFECT_REFLECT: + if (SideHasMoveSplit(battlerDef, SPLIT_PHYSICAL)) + { + if (!defHasPhysical && !defHasSpecial) + return TRUE; // Target has no attacking moves so no point in doing Light Screen check + + if (defHasPhysical || !HasMoveEffect(battlerAtk, EFFECT_LIGHT_SCREEN) || !defHasSpecial) + return TRUE; + } + break; + case EFFECT_LIGHT_SCREEN: + if (SideHasMoveSplit(battlerDef, SPLIT_SPECIAL)) + { + if (!defHasPhysical && !defHasSpecial) + return TRUE; //Target has no attacking moves so no point in doing Light Screen check + + if (defHasSpecial || !HasMoveEffect(battlerAtk, EFFECT_REFLECT) || !defHasPhysical) + return TRUE; + } + break; + } + } + return FALSE; +} + // Partner Logic bool32 IsValidDoubleBattle(u8 battlerAtk) { @@ -1681,6 +2857,74 @@ bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove return FALSE; } +bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move) +{ + u32 i; + u32 firstId, lastId; + struct Pokemon* party; + bool32 hasStatus = FALSE; + bool32 needHealing = FALSE; + + GetAIPartyIndexes(battlerAtk, &firstId, &lastId); + + if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (CountUsablePartyMons(battlerAtk) == 0 + && (CanTargetFaintAi(battlerDef, battlerAtk) || BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility))) + return FALSE; // Don't heal if last mon and will faint + + for (i = 0; i < PARTY_SIZE; i++) + { + u16 currHp = GetMonData(&party[i], MON_DATA_HP); + u16 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 (gBattleMoves[move].effect) + { + case EFFECT_WISH: + if (needHealing) + return TRUE; + break; + case EFFECT_HEAL_BELL: + if (hasStatus) + return TRUE; + } + } + else + { + switch (gBattleMoves[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; +} + // party logic s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon) { @@ -1760,3 +3004,236 @@ bool32 IsPartyFullyHealedExceptBattler(u8 battlerId) return TRUE; } +bool32 PartyHasMoveSplit(u8 battlerId, u8 split) +{ + u8 firstId, lastId; + struct Pokemon* party = GetBattlerPartyData(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++) + { + u16 move = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL); + u16 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 (gBattleMoves[move].split == split) + return TRUE; + } + } + } + + return FALSE; +} + +bool32 SideHasMoveSplit(u8 battlerId, u8 split) +{ + if (IsDoubleBattle()) + { + if (HasMoveWithSplit(battlerId, split) || HasMoveWithSplit(BATTLE_PARTNER(battlerId), split)) + return TRUE; + } + else + { + if (HasMoveWithSplit(battlerId, split)) + return TRUE; + } + return FALSE; +} + +bool32 IsAbilityOfRating(u16 ability, s8 rating) +{ + if (sAiAbilityRatings[ability] >= rating) + return TRUE; +} + +s8 GetAbilityRating(u16 ability) +{ + return sAiAbilityRatings[ability]; +} + +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, + #ifdef ITEM_EXPANSION + ITEM_FOCUS_SASH, + #endif + // TODO expand this +}; + +bool32 IsRecycleEncouragedItem(u16 item) +{ + u32 i; + for (i = 0; i < ARRAY_COUNT(sRecycleEncouragedItems); i++) + { + if (item == sRecycleEncouragedItems[i]) + return TRUE; + } + return FALSE; +} + +// score increases +#define STAT_UP_2_STAGE 8 +#define STAT_UP_STAGE 10 +void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) +{ + if (AI_DATA->atkAbility == ABILITY_CONTRARY) + return; + + switch (statId) + { + case STAT_ATK: + if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && GetHealthPercentage(battlerAtk) > 40) + { + if (gBattleMons[battlerAtk].statStages[STAT_ATK] < STAT_UP_2_STAGE) + *score += 2; + else if (gBattleMons[battlerAtk].statStages[STAT_ATK] < STAT_UP_STAGE) + *(score)++; + } + if (HasMoveEffect(battlerAtk, EFFECT_FOUL_PLAY)) + *(score)++; + break; + case STAT_DEF: + if ((HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)|| IS_MOVE_PHYSICAL(gLastMoves[battlerDef])) + && GetHealthPercentage(battlerAtk) > 70) + { + if (gBattleMons[battlerAtk].statStages[STAT_DEF] < STAT_UP_2_STAGE) + *score += 2; // seems better to raise def at higher HP + else if (gBattleMons[battlerAtk].statStages[STAT_DEF] < STAT_UP_STAGE) + *(score)++; + } + break; + case STAT_SPEED: + if (IsAiFaster(AI_CHECK_SLOWER)) + *score += 3; + break; + case STAT_SPATK: + if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && GetHealthPercentage(battlerAtk) > 40) + { + if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < STAT_UP_2_STAGE) + *score += 2; + else if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < STAT_UP_STAGE) + *(score)++; + } + break; + case STAT_SPDEF: + if ((HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) || IS_MOVE_SPECIAL(gLastMoves[battlerDef])) + && GetHealthPercentage(battlerAtk) > 70) + { + if (gBattleMons[battlerAtk].statStages[STAT_SPDEF] < STAT_UP_2_STAGE) + *score += 2; // seems better to raise spdef at higher HP + else if (gBattleMons[battlerAtk].statStages[STAT_SPDEF] < STAT_UP_STAGE) + *(score)++; + } + break; + case STAT_ACC: + if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + *score += 3; // has moves with less than 80% accuracy + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + *score += 2; + break; + case STAT_EVASION: + if (!BattlerWillFaintFromWeather(battlerAtk, AI_DATA->atkAbility)) + { + if (!GetBattlerSecondaryDamage(battlerAtk) && !(gStatuses3[battlerAtk] & STATUS3_ROOTED)) + *score += 3; + else + *score += 2; + } + break; + } +} + +void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +{ + if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove) && GetHealthPercentage(battlerDef) > 20) + { + if (!HasDamagingMove(battlerDef)) + *score += 2; + + if (HasMoveEffect(battlerAtk, EFFECT_PROTECT)) + (*score)++; // stall tactic + + if (HasMoveEffect(battlerAtk, EFFECT_VENOSHOCK) + || HasMoveEffect(battlerAtk, EFFECT_HEX) + || HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH) + || AI_DATA->atkAbility == ABILITY_MERCILESS) + *score += 4; + else + *score += 2; + } +} + +void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +{ + if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + { + (*score)++; // burning is good + if (HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) + { + if (CanTargetFaintAi(battlerDef, battlerAtk)) + *score += 2; // burning the target to stay alive is cool + } + + if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_HEX)) + (*score)++; + } +} + +void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +{ + if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + { + u8 atkSpeed = GetBattlerTotalSpeedStat(battlerAtk); + u8 defSpeed = GetBattlerTotalSpeedStat(battlerDef); + + if ((defSpeed >= atkSpeed && defSpeed / 2 < atkSpeed) // You'll go first after paralyzing foe + || HasMoveEffect(battlerAtk, EFFECT_HEX) + || HasMoveEffect(battlerAtk, EFFECT_FLINCH_HIT) + || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION + || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + *score += 4; + else + *score += 2; + } +} + +void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +{ + if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + *score += 3; + + if ((HasMoveEffect(battlerAtk, EFFECT_DREAM_EATER) || HasMoveEffect(battlerAtk, EFFECT_NIGHTMARE)) + && !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) + (*score)++; + + if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_HEX)) + (*score)++; +} + +void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +{ + if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) + && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_CONFUSION + && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_STATUS) + { + if (gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS + || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION + || (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && HasMoveEffect(battlerAtk, EFFECT_FLINCH_HIT))) + *score += 3; + else + *score += 2; + } +} diff --git a/src/item.c b/src/item.c index 0b63660480..a0ab61779d 100644 --- a/src/item.c +++ b/src/item.c @@ -957,3 +957,26 @@ u8 ItemId_GetSecondaryId(u16 itemId) { return gItems[SanitizeItemId(itemId)].secondaryId; } + +bool32 IsPinchBerryItemEffect(u16 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: + #ifdef HOLD_EFFECT_CUSTAP_BERRY + case HOLD_EFFECT_CUSTAP_BERRY: + #endif + #ifdef HOLD_EFFECT_MICLE_BERRY + case HOLD_EFFECT_MICLE_BERRY: + #endif + return TRUE; + } + + return FALSE; +} From cd119ed6c3fc45096437df710f0646e0a1d3b5a9 Mon Sep 17 00:00:00 2001 From: Evan Date: Sat, 19 Dec 2020 22:07:21 -0700 Subject: [PATCH 08/36] first turn ai script --- data/battle_ai_scripts.s | 90 -------------------------------- src/battle_ai_script_commands.c | 91 +++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 90 deletions(-) diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index 0ea7573740..0f53c81ea5 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -3344,98 +3344,8 @@ AI_CV_DragonDance_End: AI_SetupFirstTurn: - if_target_is_ally AI_Ret - get_turn_count - if_not_equal 0, AI_SetupFirstTurn_End - get_considered_move_effect - if_not_in_hwords AI_SetupFirstTurn_SetupEffectsToEncourage, AI_SetupFirstTurn_End - score +2 -AI_SetupFirstTurn_End: end -.align 1 -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_ACUPRESSURE - .2byte EFFECT_AUTOTOMIZE - .2byte EFFECT_SHIFT_GEAR - .2byte EFFECT_SHELL_SMASH - .2byte EFFECT_GROWTH - .2byte EFFECT_QUIVER_DANCE - .2byte EFFECT_ATTACK_SPATK_UP - .2byte EFFECT_ATTACK_ACCURACY_UP - .2byte EFFECT_PSYCHIC_TERRAIN - .2byte EFFECT_GRASSY_TERRAIN - .2byte EFFECT_ELECTRIC_TERRAIN - .2byte EFFECT_MISTY_TERRAIN - .2byte EFFECT_STEALTH_ROCK - .2byte EFFECT_TOXIC_SPIKES - .2byte EFFECT_TRICK_ROOM - .2byte EFFECT_WONDER_ROOM - .2byte EFFECT_MAGIC_ROOM - .2byte EFFECT_TAILWIND - .2byte EFFECT_DRAGON_DANCE - .2byte EFFECT_STICKY_WEB - .2byte EFFECT_RAIN_DANCE - .2byte EFFECT_SUNNY_DAY - .2byte EFFECT_SANDSTORM - .2byte EFFECT_HAIL - .2byte EFFECT_GEOMANCY - .2byte -1 - AI_PreferStrongestMove: if_target_is_ally AI_Ret get_how_powerful_move_is diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 0c1382a51f..fa6510bbaa 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -5912,8 +5912,99 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } +// Effects that are encouraged on the first turn of battle static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { + if (IsTargetingPartner(battlerAtk, battlerDef) + || gBattleResults.battleTurnCounter != 0) + return score; + switch (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect) + { + case EFFECT_ATTACK_UP: + 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_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_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_TEETER_DANCE: + 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_STICKY_WEB: + case EFFECT_RAIN_DANCE: + case EFFECT_SUNNY_DAY: + case EFFECT_SANDSTORM: + case EFFECT_HAIL: + case EFFECT_GEOMANCY: + score += 2; + break; + default: + break; + } + + return score; } static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) From b2e57604790ddad3df0b64cdb49a911f790b1bb7 Mon Sep 17 00:00:00 2001 From: Evan Date: Sat, 19 Dec 2020 22:12:31 -0700 Subject: [PATCH 09/36] risky ai script -> c --- data/battle_ai_scripts.s | 30 +-------------------------- src/battle_ai_script_commands.c | 36 ++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index 0f53c81ea5..15752259bc 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -3356,37 +3356,9 @@ AI_PreferStrongestMove_End: end AI_Risky: - if_target_is_ally AI_Ret - get_considered_move_effect - if_move_flag FLAG_HIGH_CRIT, AI_Risky_RandChance - if_not_in_bytes AI_Risky_EffectsToEncourage, AI_Risky_End -AI_Risky_RandChance: - if_random_less_than 128, AI_Risky_End - score +2 -AI_Risky_End: end -AI_Risky_EffectsToEncourage: - .byte EFFECT_SLEEP - .byte EFFECT_EXPLOSION - .byte EFFECT_MIRROR_MOVE - .byte EFFECT_OHKO - .byte EFFECT_CONFUSE - .byte EFFECT_METRONOME - .byte EFFECT_PSYWAVE - .byte EFFECT_COUNTER - .byte EFFECT_DESTINY_BOND - .byte EFFECT_SWAGGER - .byte EFFECT_ATTRACT - .byte EFFECT_PRESENT - .byte EFFECT_ALL_STATS_UP_HIT - .byte EFFECT_BELLY_DRUM - .byte EFFECT_MIRROR_COAT - .byte EFFECT_FOCUS_PUNCH - .byte EFFECT_REVENGE - .byte EFFECT_TEETER_DANCE - .byte -1 - + .align 1 sMovesTable_ProtectMoves: .2byte MOVE_PROTECT diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index fa6510bbaa..22087be14f 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -5918,7 +5918,7 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsTargetingPartner(battlerAtk, battlerDef) || gBattleResults.battleTurnCounter != 0) return score; - switch (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect) + switch (gBattleMoves[move].effect) { case EFFECT_ATTACK_UP: case EFFECT_DEFENSE_UP: @@ -6009,6 +6009,40 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { + if (IsTargetingPartner(battlerAtk, battlerDef)) + return score; + + if (TestMoveFlags(move, FLAG_HIGH_CRIT)) + score += 2; + + switch (gBattleMoves[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_ALL_STATS_UP_HIT: + case EFFECT_BELLY_DRUM: + case EFFECT_MIRROR_COAT: + case EFFECT_FOCUS_PUNCH: + case EFFECT_REVENGE: + case EFFECT_TEETER_DANCE: + if (Random() & 1) + score += 2; + break; + default: + break; + } + + return score; } static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) From a504199ea67708f5dfaa1d8fa80e852fe95bbc89 Mon Sep 17 00:00:00 2001 From: Evan Date: Sat, 19 Dec 2020 22:51:25 -0700 Subject: [PATCH 10/36] ai prefer baton pass --- data/battle_ai_scripts.s | 69 ----------------------- src/battle_ai_script_commands.c | 99 +++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 69 deletions(-) diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index 15752259bc..5ab6d15745 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -3347,81 +3347,12 @@ AI_SetupFirstTurn: end AI_PreferStrongestMove: - if_target_is_ally AI_Ret - get_how_powerful_move_is - if_not_equal MOVE_POWER_BEST, AI_PreferStrongestMove_End - if_random_less_than 100, AI_PreferStrongestMove_End - score +2 -AI_PreferStrongestMove_End: end AI_Risky: end - -.align 1 -sMovesTable_ProtectMoves: - .2byte MOVE_PROTECT - .2byte MOVE_DETECT - .2byte -1 - -.align 1 -sEffectsStatRaise: - .2byte EFFECT_ATTACK_UP - .2byte EFFECT_ATTACK_UP_2 - .2byte EFFECT_DEFENSE_UP - .2byte EFFECT_DEFENSE_UP_2 - .2byte EFFECT_SPEED_UP - .2byte EFFECT_SPEED_UP_2 - .2byte EFFECT_SPECIAL_ATTACK_UP - .2byte EFFECT_SPECIAL_ATTACK_UP_2 - .2byte EFFECT_SPECIAL_DEFENSE_UP - .2byte EFFECT_SPECIAL_DEFENSE_UP_2 - .2byte EFFECT_CALM_MIND - .2byte EFFECT_DRAGON_DANCE - .2byte EFFECT_ACUPRESSURE - .2byte EFFECT_SHELL_SMASH - .2byte EFFECT_SHIFT_GEAR - .2byte EFFECT_ATTACK_ACCURACY_UP - .2byte EFFECT_ATTACK_SPATK_UP - .2byte EFFECT_GROWTH - .2byte EFFECT_COIL - .2byte EFFECT_QUIVER_DANCE - .2byte -1 - AI_PreferBatonPass: - if_target_is_ally AI_Ret - count_usable_party_mons AI_USER - if_equal 0, AI_PreferBatonPassEnd - get_how_powerful_move_is - if_not_equal MOVE_POWER_DISCOURAGED, AI_PreferBatonPassEnd - if_doesnt_have_move_with_effect AI_USER, EFFECT_BATON_PASS, AI_PreferBatonPassEnd - get_considered_move_effect - if_in_hwords sEffectsStatRaise, AI_PreferBatonPass2 - if_effect EFFECT_PROTECT, AI_PreferBatonPass3 - if_move MOVE_BATON_PASS, AI_PreferBatonPass_EncourageIfHighStats - end -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_bank_move AI_USER - if_in_hwords sMovesTable_ProtectMoves, Score_Minus2 - score +2 - end -AI_PreferBatonPass_EncourageIfHighStats: - get_turn_count - if_equal 0, Score_Minus2 - if_stat_level_more_than AI_USER, STAT_ATK, DEFAULT_STAT_STAGE + 2, Score_Plus3 - if_stat_level_more_than AI_USER, STAT_ATK, DEFAULT_STAT_STAGE + 1, Score_Plus2 - if_stat_level_more_than AI_USER, STAT_ATK, DEFAULT_STAT_STAGE, Score_Plus1 - if_stat_level_more_than AI_USER, STAT_SPATK, DEFAULT_STAT_STAGE + 2, Score_Plus3 - if_stat_level_more_than AI_USER, STAT_SPATK, DEFAULT_STAT_STAGE + 1, Score_Plus2 - if_stat_level_more_than AI_USER, STAT_SPATK, DEFAULT_STAT_STAGE, Score_Plus1 - end -AI_PreferBatonPassEnd: end AI_ConsiderAllyChosenMove: diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 22087be14f..062bfe63cb 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -2674,6 +2674,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_DEFENSE_UP: case EFFECT_DEFENSE_UP_2: + case EFFECT_DEFENSE_UP_3: case EFFECT_DEFENSE_CURL: if (move == MOVE_STUFF_CHEEKS) { @@ -2728,6 +2729,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SPECIAL_ATTACK_UP: case EFFECT_SPECIAL_ATTACK_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_3: if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) @@ -4465,6 +4467,7 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_DEFENSE_UP: case EFFECT_DEFENSE_UP_2: + case EFFECT_DEFENSE_UP_3: IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score); break; case EFFECT_SPEED_UP: @@ -4473,6 +4476,7 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SPECIAL_ATTACK_UP: case EFFECT_SPECIAL_ATTACK_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_3: IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score); break; case EFFECT_SPECIAL_DEFENSE_UP: @@ -5940,8 +5944,10 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) 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: @@ -6007,6 +6013,7 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } +// Adds score bonus to 'riskier' move effects and high crit moves static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (IsTargetingPartner(battlerAtk, battlerDef)) @@ -6045,12 +6052,101 @@ static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } +// Adds score bonus to best powered move static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { + if (IsTargetingPartner(battlerAtk, battlerDef)) + return score; + + if (GetMoveDamageResult(move) == MOVE_POWER_BEST) + score += 2; + + return score; } +// Prefers moves that are good for baton pass static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { + u32 i; + + if (IsTargetingPartner(battlerAtk, battlerDef) + || CountUsablePartyMons(battlerAtk) == 0 + || GetMoveDamageResult(move) != MOVE_POWER_DISCOURAGED + || !HasMoveEffect(battlerAtk, EFFECT_BATON_PASS) + || IsBattlerTrapped(battlerAtk, TRUE)) + return score; + + switch (gBattleMoves[move].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_CHARGE: + 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: + if (gBattleResults.battleTurnCounter == 0) + score += 5; + else if (GetHealthPercentage(battlerAtk) < 60) + score -= 10; + else + score++; + break; + case EFFECT_INGRAIN: + if (!(gStatuses3[battlerAtk] & STATUS3_ROOTED)) + score += 2; + break; + case EFFECT_AQUA_RING: + if (!(gStatuses3[battlerAtk] & STATUS3_AQUA_RING)) + score += 2; + break; + case EFFECT_PROTECT: + if (gLastMoves[battlerAtk] == MOVE_PROTECT || gLastMoves[battlerAtk] == MOVE_DETECT) + score -= 2; + else + score += 2; + break; + case EFFECT_BATON_PASS: + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) + { + IncreaseStatUpScore(battlerAtk, battlerDef, i, &score); + } + if (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING)) + score += 2; + if (gStatuses3[battlerAtk] & STATUS3_LEECHSEED) + score -= 3; + break; + default: + break; + } + + return score; } static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) @@ -6071,6 +6167,7 @@ static void AI_Watch(void) AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); } +// Roaming pokemon logic static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (IsBattlerTrapped(battlerAtk, FALSE)) @@ -6080,6 +6177,7 @@ static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } +// Safari pokemon logic static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { u8 safariFleeRate = gBattleStruct->safariEscapeFactor * 5; // Safari flee rate, from 0-20. @@ -6092,6 +6190,7 @@ static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } +// First battle logic static s16 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (GetHealthPercentage(battlerDef) <= 20) From c5597e2e181288cab140197af9bb082c1bab9780 Mon Sep 17 00:00:00 2001 From: Evan Date: Sat, 19 Dec 2020 22:57:08 -0700 Subject: [PATCH 11/36] fix first battle bug --- src/battle_ai_script_commands.c | 57 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 062bfe63cb..55597e98a6 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -45,8 +45,6 @@ in order to read the next command correctly. refer to battle_ai_scripts.s for th AI scripts. */ -extern const u8 *const gBattleAI_ScriptsTable[]; - static u8 ChooseMoveOrAction_Singles(void); static u8 ChooseMoveOrAction_Doubles(void); static void BattleAI_DoAIProcessing(void); @@ -755,7 +753,6 @@ static void BattleAI_DoAIProcessing(void) case AIState_DoNotProcess: // Needed to match. break; case AIState_SettingUp: - gAIScriptPtr = gBattleAI_ScriptsTable[AI_THINKING_STRUCT->aiLogicId]; // set AI ptr to logic ID. if (gBattleMons[sBattler_AI].pp[AI_THINKING_STRUCT->movesetIndex] == 0) { AI_THINKING_STRUCT->moveConsidered = 0; @@ -767,33 +764,30 @@ static void BattleAI_DoAIProcessing(void) AI_THINKING_STRUCT->aiState++; break; case AIState_Processing: - if (AI_THINKING_STRUCT->moveConsidered != MOVE_NONE) - { - if (AI_THINKING_STRUCT->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable) && sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId] != NULL) - { - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] += sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId](sBattler_AI, - gBattlerTarget, AI_THINKING_STRUCT->moveConsidered, AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex]); - if (AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] < 0) - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; // limit to 0 - } - } - 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->moveConsidered != MOVE_NONE + && AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] > 0) + { + if (AI_THINKING_STRUCT->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable) + && sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId] != NULL) + { + // Call AI function + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = + sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId](gBattlerAttacker, + gBattlerTarget, + AI_THINKING_STRUCT->moveConsidered, + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex]); + } + } + else + { + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; + } - if (AI_THINKING_STRUCT->movesetIndex < MAX_MON_MOVES && !(AI_THINKING_STRUCT->aiAction & AI_ACTION_DO_NOT_ATTACK)) - AI_THINKING_STRUCT->aiState = AIState_SettingUp; - else - AI_THINKING_STRUCT->aiState++; - - 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)) + AI_THINKING_STRUCT->aiState = AIState_SettingUp; + else + AI_THINKING_STRUCT->aiState++; break; } } @@ -4313,6 +4307,9 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && IS_MOVE_STATUS(move)) score -= 10; //Don't use a status move if partner wants to help + if (score < 0) + score = 0; + return score; } @@ -6151,10 +6148,12 @@ static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { + return score; } static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { + return score; } static void AI_Flee(void) From 7988a1f41d0b20019b0ad157fc222c4035d0e976 Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 20 Dec 2020 14:47:20 -0700 Subject: [PATCH 12/36] Ai_TryOnAlly and reorganize files --- data/battle_ai_scripts.s | 3847 ----------------- include/battle.h | 1 - ..._ai_script_commands.h => battle_ai_main.h} | 9 +- include/battle_ai_util.h | 9 +- include/constants/battle_ai.h | 11 +- ld_script.txt | 5 +- ..._ai_script_commands.c => battle_ai_main.c} | 2387 ++-------- src/battle_ai_switch_items.c | 2 +- src/battle_ai_util.c | 153 +- src/battle_controller_link_opponent.c | 2 +- src/battle_controller_link_partner.c | 2 +- src/battle_controller_opponent.c | 2 +- src/battle_controller_player_partner.c | 2 +- src/battle_controller_recorded_opponent.c | 2 +- src/battle_controller_recorded_player.c | 2 +- src/battle_controllers.c | 2 +- src/battle_debug.c | 3 +- src/battle_gfx_sfx_util.c | 2 +- src/battle_main.c | 2 +- src/battle_script_commands.c | 2 +- src/battle_util.c | 2 +- src/battle_util2.c | 2 - sym_ewram.txt | 2 +- 23 files changed, 641 insertions(+), 5812 deletions(-) delete mode 100644 data/battle_ai_scripts.s rename include/{battle_ai_script_commands.h => battle_ai_main.h} (53%) rename src/{battle_ai_script_commands.c => battle_ai_main.c} (77%) diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s deleted file mode 100644 index 5ab6d15745..0000000000 --- a/data/battle_ai_scripts.s +++ /dev/null @@ -1,3847 +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 - - .align 2 -gBattleAI_ScriptsTable:: @ 82DBEF8 - .4byte AI_CheckBadMove @ AI_SCRIPT_CHECK_BAD_MOVE - .4byte AI_TryToFaint @ AI_SCRIPT_TRY_TO_FAINT - .4byte AI_CheckViability @ AI_SCRIPT_CHECK_VIABILITY - .4byte AI_SetupFirstTurn @ AI_SCRIPT_SETUP_FIRST_TURN - .4byte AI_Risky @ AI_SCRIPT_RISKY - .4byte AI_PreferStrongestMove @ AI_SCRIPT_PREFER_STRONGEST_MOVE - .4byte AI_PreferBatonPass @ AI_SCRIPT_PREFER_BATON_PASS - .4byte AI_DoubleBattle @ AI_SCRIPT_DOUBLE_BATTLE - .4byte AI_HPAware @ AI_SCRIPT_HP_AWARE - -AI_TryToFaint: - -AI_CheckBadMove: - if_target_is_ally AI_Ret -@ Check powder moves - if_move_flag FLAG_POWDER, AI_CBM_PowderMoves - goto AI_CBM_CheckIfNegatesType -AI_CBM_PowderMoves: - if_type AI_TARGET, TYPE_GRASS, Score_Minus10 - if_ability AI_TARGET, ABILITY_OVERCOAT, Score_Minus10 - get_hold_effect AI_TARGET - if_equal HOLD_EFFECT_SAFETY_GOOGLES Score_Minus10 - -AI_CBM_CheckIfNegatesType: - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - get_ability AI_USER - if_equal ABILITY_MOLD_BREAKER, AI_CheckBadMove_CheckEffect - if_equal ABILITY_TERAVOLT, AI_CheckBadMove_CheckEffect - if_equal ABILITY_TURBOBLAZE, AI_CheckBadMove_CheckEffect - get_ability AI_TARGET - if_equal ABILITY_VOLT_ABSORB, CheckIfVoltAbsorbCancelsElectric - if_equal ABILITY_LIGHTNING_ROD, CheckIfVoltAbsorbCancelsElectric - if_equal ABILITY_MOTOR_DRIVE, CheckIfVoltAbsorbCancelsElectric - if_equal ABILITY_WATER_ABSORB, CheckIfWaterAbsorbCancelsWater - if_equal ABILITY_STORM_DRAIN, CheckIfWaterAbsorbCancelsWater - if_equal ABILITY_DRY_SKIN, CheckIfWaterAbsorbCancelsWater - if_equal ABILITY_FLASH_FIRE, CheckIfFlashFireCancelsFire - if_equal ABILITY_WONDER_GUARD, CheckIfWonderGuardCancelsMove - if_equal ABILITY_LEVITATE, CheckIfLevitateCancelsGroundMove - if_equal ABILITY_SOUNDPROOF, CheckIfSoundproofCancelsMove - goto AI_CheckBadMove_CheckEffect - -CheckIfSoundproofCancelsMove: - if_move_flag FLAG_SOUND, Score_Minus10 - goto AI_CheckBadMove_CheckEffect - -CheckIfVoltAbsorbCancelsElectric: @ 82DBFBD - get_curr_move_type - if_equal TYPE_ELECTRIC, Score_Minus12 - goto AI_CheckBadMove_CheckEffect - -CheckIfWaterAbsorbCancelsWater: @ 82DBFCA - get_curr_move_type - if_equal TYPE_WATER, Score_Minus12 - goto AI_CheckBadMove_CheckEffect - -CheckIfFlashFireCancelsFire: @ 82DBFD7 - get_curr_move_type - if_equal TYPE_FIRE, Score_Minus12 - goto AI_CheckBadMove_CheckEffect - -CheckIfWonderGuardCancelsMove: @ 82DBFE4 - if_type_effectiveness AI_EFFECTIVENESS_x2, AI_CheckBadMove_CheckEffect - if_type_effectiveness AI_EFFECTIVENESS_x4, AI_CheckBadMove_CheckEffect - goto Score_Minus10 - -CheckIfLevitateCancelsGroundMove: @ 82DBFEF - get_curr_move_type - if_equal TYPE_GROUND, Score_Minus10 - -AI_CheckBadMove_CheckEffect: @ 82DC045 - 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_Toxic - if_effect EFFECT_LIGHT_SCREEN, AI_CBM_LightScreen - if_effect EFFECT_OHKO, AI_CBM_OneHitKO - 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_Toxic - 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_CAPTIVATE, AI_CBM_Captivate - 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 - if_effect EFFECT_STICKY_WEB, AI_CBM_StickyWeb - if_effect EFFECT_STEALTH_ROCK, AI_CBM_StealthRock - if_effect EFFECT_TOXIC_SPIKES, AI_CBM_ToxicSpikes - if_effect EFFECT_AQUA_RING, AI_CBM_AquaRing - if_effect EFFECT_GRAVITY, AI_CBM_Gravity - if_effect EFFECT_EMBARGO, AI_CBM_Embargo - if_effect EFFECT_LUCKY_CHANT, AI_CBM_LuckyChant - if_effect EFFECT_HEAL_PULSE, Score_Minus5 - if_effect EFFECT_QUASH, AI_CBM_Quash - if_effect EFFECT_GASTRO_ACID, AI_CBM_GastroAcid - if_effect EFFECT_HEAL_BLOCK, AI_CBM_HealBlock - if_effect EFFECT_WORRY_SEED, AI_CBM_WorrySeed - if_effect EFFECT_MIRACLE_EYE, AI_CBM_MiracleEye - if_effect EFFECT_MAGNET_RISE, AI_CBM_MagnetRise - if_effect EFFECT_TELEKINESIS, AI_CBM_Telekinesis - if_effect EFFECT_MISTY_TERRAIN, AI_CBM_MistyTerrain - if_effect EFFECT_GRASSY_TERRAIN, AI_CBM_GrassyTerrain - if_effect EFFECT_ELECTRIC_TERRAIN, AI_CBM_ElectricTerrain - if_effect EFFECT_PSYCHIC_TERRAIN, AI_CBM_PsychicTerrain - if_effect EFFECT_QUIVER_DANCE, AI_CBM_QuiverDance - if_effect EFFECT_COIL, AI_CBM_Coil - if_effect EFFECT_TAILWIND, AI_CBM_Tailwind - if_effect EFFECT_SIMPLE_BEAM, AI_CBM_SimpleBeam - if_effect EFFECT_NATURAL_GIFT, AI_CBM_NaturalGift - if_effect EFFECT_FLING, AI_CBM_Fling - if_effect EFFECT_ATTACK_ACCURACY_UP, AI_CBM_AtkAccUp - if_effect EFFECT_ATTACK_SPATK_UP, AI_CBM_AtkSpAtkUp - if_effect EFFECT_GROWTH, AI_CBM_AtkSpAtkUp - if_effect EFFECT_AROMATIC_MIST, AI_CBM_AromaticMist - if_effect EFFECT_ACUPRESSURE, AI_CBM_Acupressure - if_effect EFFECT_BESTOW, AI_CBM_Bestow - if_effect EFFECT_PSYCHO_SHIFT, AI_CBM_PsychicShift - if_effect EFFECT_DEFOG, AI_CBM_Defog - if_effect EFFECT_SYNCHRONOISE, AI_CBM_Synchronoise - if_effect EFFECT_AUTOTOMIZE, AI_CBM_SpeedUp - if_effect EFFECT_TOXIC_THREAD, AI_CBM_ToxicThread - if_effect EFFECT_VENOM_DRENCH, AI_CBM_VenomDrench - if_effect EFFECT_DEFENSE_UP_3, AI_CBM_DefenseUp - if_effect EFFECT_SHIFT_GEAR, AI_CBM_DragonDance - if_effect EFFECT_NOBLE_ROAR, AI_CBM_NobleRoar - if_effect EFFECT_SHELL_SMASH, AI_CBM_ShellSmash - if_effect EFFECT_LAST_RESORT, AI_CBM_LastResort - if_effect EFFECT_BELCH, AI_CBM_Belch - if_effect EFFECT_DO_NOTHING, Score_Minus8 - if_effect EFFECT_POWDER, AI_CBM_Powder - if_effect EFFECT_PROTECT, AI_CBM_Protect - if_effect EFFECT_TAUNT, AI_CBM_Taunt - if_effect EFFECT_HEAL_BELL, AI_CBM_HealBell - if_effect EFFECT_FOLLOW_ME, AI_CBM_FollowMe - if_effect EFFECT_GEOMANCY, AI_CBM_QuiverDance - if_effect EFFECT_FAIRY_LOCK, AI_CBM_FairyLock - if_effect EFFECT_ALLY_SWITCH, AI_CBM_HelpingHand - if_effect EFFECT_TRICK_ROOM, AI_CBM_TrickRoom - if_effect EFFECT_WONDER_ROOM, AI_CBM_WonderRoom - if_effect EFFECT_MAGIC_ROOM, AI_CBM_MagicRoom - if_effect EFFECT_SOAK, AI_CBM_Soak - if_effect EFFECT_LOCK_ON, AI_CBM_LockOn - end - -AI_CBM_LockOn: - if_status3 AI_TARGET, STATUS3_ALWAYS_HITS, Score_Minus10 - if_ability AI_TARGET, ABILITY_NO_GUARD, Score_Minus10 - if_ability AI_USER, ABILITY_NO_GUARD, Score_Minus10 - end - -AI_CBM_Soak: - if_type AI_TARGET, TYPE_WATER, Score_Minus10 - end - -AI_CBM_TrickRoom: - if_field_status STATUS_FIELD_TRICK_ROOM, Score_Minus10 - end - -AI_CBM_WonderRoom: - if_field_status STATUS_FIELD_WONDER_ROOM, Score_Minus10 - end - -AI_CBM_MagicRoom: - if_field_status STATUS_FIELD_MAGIC_ROOM, Score_Minus10 - end - -AI_CBM_FairyLock: - if_field_status STATUS_FIELD_FAIRY_LOCK, Score_Minus10 - if_status2 AI_TARGET, STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED, Score_Minus10 - end - -AI_CBM_Geomancy: - call AI_CBM_QuiverDance - end - -AI_CBM_FollowMe: - if_not_double_battle Score_Minus10 - if_battler_absent AI_USER_PARTNER, Score_Minus10 - end - -AI_CBM_HealBell: - if_status AI_TARGET, STATUS1_ANY, AI_CBM_HealBell_End - if_status_in_party AI_TARGET, STATUS1_ANY, AI_CBM_HealBell_End - score -5 -AI_CBM_HealBell_End: - end - -AI_CBM_Taunt: - if_target_taunted Score_Minus10 - end - -AI_CBM_Protect: - get_protect_count AI_USER - if_more_than 2, Score_Minus10 - if_status AI_TARGET, STATUS1_SLEEP | STATUS1_FREEZE, Score_Minus8 - end - -AI_CBM_Powder: - if_type AI_TARGET, TYPE_FIRE, AI_Ret - if_has_move_with_type AI_TARGET, TYPE_FIRE, AI_Ret - score -5 - end - -AI_CBM_Belch: - if_cant_use_belch AI_USER, Score_Minus10 - end - -AI_CBM_LastResort: - if_cant_use_last_resort AI_USER, Score_Minus10 - end - -AI_CBM_ShellSmash: - if_ability AI_USER, ABILITY_CONTRARY, AI_CBM_ShellSmashContrary - if_stat_level_not_equal AI_USER, STAT_SPATK, 12, AI_Ret - if_stat_level_not_equal AI_USER, STAT_SPEED, 12, AI_Ret - if_stat_level_equal AI_USER, STAT_ATK, 12, Score_Minus10 - end -AI_CBM_ShellSmashContrary: - if_stat_level_not_equal AI_USER, STAT_DEF, 12, AI_Ret - if_stat_level_equal AI_USER, STAT_SPDEF, 12, Score_Minus10 - end - -AI_CBM_NobleRoar: - if_stat_level_not_equal AI_TARGET, STAT_SPATK, 12, AI_Ret - if_stat_level_equal AI_TARGET, STAT_ATK, 12, Score_Minus10 - end - -AI_CBM_VenomDrench: - if_not_status AI_TARGET, STATUS1_PSN_ANY, Score_Minus10 - if_stat_level_not_equal AI_TARGET, STAT_SPEED, 12, AI_Ret - if_stat_level_not_equal AI_TARGET, STAT_SPATK, 12, AI_Ret - if_stat_level_equal AI_TARGET, STAT_ATK, 12, Score_Minus10 - end - -AI_CBM_ToxicThread: - if_stat_level_not_equal AI_TARGET, STAT_SPEED, 12, AI_Ret - goto AI_CBM_Toxic - -AI_CBM_Synchronoise: - if_share_type AI_USER, AI_TARGET AI_Ret - goto Score_Minus10 - -AI_CBM_Defog: - if_side_affecting AI_USER, SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_STICKY_WEB, AI_Ret - goto AI_CBM_EvasionDown - -AI_CBM_PsychicShift: - if_not_status AI_USER, STATUS1_ANY, Score_Minus10 - if_status AI_TARGET, STATUS1_ANY, Score_Minus10 - if_status AI_USER, STATUS1_PARALYSIS, AI_CBM_Paralyze - if_status AI_USER, STATUS1_PSN_ANY, AI_CBM_Toxic - if_status AI_USER, STATUS1_BURN, AI_CBM_WillOWisp - if_status AI_USER, STATUS1_SLEEP, AI_CBM_Sleep - end - -AI_CBM_Bestow: - if_holds_no_item AI_USER, Score_Minus10 - end - -AI_CBM_Acupressure: - if_double_battle AI_Ret - if_stat_level_not_equal AI_USER, STAT_ATK, 12, AI_Ret - if_stat_level_not_equal AI_USER, STAT_DEF, 12, AI_Ret - if_stat_level_not_equal AI_USER, STAT_SPATK, 12, AI_Ret - if_stat_level_not_equal AI_USER, STAT_SPDEF, 12, AI_Ret - if_stat_level_not_equal AI_USER, STAT_SPEED, 12, AI_Ret - if_stat_level_not_equal AI_USER, STAT_ACC, 12, AI_Ret - if_stat_level_equal AI_USER, STAT_EVASION, 12, Score_Minus10 - end - -AI_CBM_AromaticMist: - if_target_is_ally AI_Ret - goto Score_Minus10 - -AI_CBM_AtkAccUp: - if_stat_level_not_equal AI_USER, STAT_ATK, 12, AI_Ret - if_stat_level_equal AI_USER, STAT_ACC, 12, Score_Minus10 - end - -AI_CBM_AtkSpAtkUp: - if_stat_level_not_equal AI_USER, STAT_ATK, 12, AI_Ret - if_stat_level_equal AI_USER, STAT_SPATK, 12, Score_Minus10 - end - -AI_CBM_Fling: - if_holds_no_item AI_USER, Score_Minus10 - if_ability AI_USER, ABILITY_KLUTZ, Score_Minus10 - if_status3 AI_USER, STATUS3_EMBARGO, Score_Minus10 - if_field_status STATUS_FIELD_MAGIC_ROOM, Score_Minus10 - end - -AI_CBM_NaturalGift: - if_doesnt_hold_berry AI_USER, Score_Minus10 - if_ability AI_USER, ABILITY_KLUTZ, Score_Minus10 - if_status3 AI_USER, STATUS3_EMBARGO, Score_Minus10 - if_field_status STATUS_FIELD_MAGIC_ROOM, Score_Minus10 - end - -AI_CBM_SimpleBeam: - if_ability AI_TARGET, ABILITY_SIMPLE, Score_Minus10 - end - -AI_CBM_Tailwind: - if_side_affecting AI_USER, SIDE_STATUS_TAILWIND, Score_Minus10 - end - -AI_CBM_QuiverDance: - if_stat_level_not_equal AI_USER, STAT_SPATK, 12, AI_Ret - if_stat_level_not_equal AI_USER, STAT_SPDEF, 12, AI_Ret - if_stat_level_equal AI_USER, STAT_SPEED, 12, Score_Minus10 - end - -AI_CBM_Coil: - if_stat_level_not_equal AI_USER, STAT_ATK, 12, AI_Ret - if_stat_level_not_equal AI_USER, STAT_DEF, 12, AI_Ret - if_stat_level_equal AI_USER, STAT_ACC, 12, Score_Minus10 - end - -AI_CBM_MistyTerrain: - if_field_status STATUS_FIELD_MISTY_TERRAIN, Score_Minus10 - end - -AI_CBM_GrassyTerrain: - if_field_status STATUS_FIELD_GRASSY_TERRAIN, Score_Minus10 - end - -AI_CBM_ElectricTerrain: - if_field_status STATUS_FIELD_ELECTRIC_TERRAIN, Score_Minus10 - end - -AI_CBM_PsychicTerrain: - if_field_status STATUS_FIELD_PSYCHIC_TERRAIN, Score_Minus10 - end - -AI_CBM_Quash: - if_not_double_battle Score_Minus10 - end - -AI_CBM_Telekinesis: - if_status3 AI_TARGET, STATUS3_TELEKINESIS, Score_Minus10 - end - -AI_CBM_MagnetRise: - if_status3 AI_USER, STATUS3_MAGNET_RISE, Score_Minus10 - end - -AI_CBM_MiracleEye: - if_status3 AI_TARGET, STATUS3_MIRACLE_EYED, Score_Minus10 - if_status2 AI_TARGET, STATUS2_FORESIGHT, Score_Minus10 - end - -AI_CBM_WorrySeed: - get_ability AI_TARGET - if_equal ABILITY_INSOMNIA, Score_Minus10 - if_equal ABILITY_VITAL_SPIRIT, Score_Minus10 - end - -AI_CBM_HealBlock: - if_status3 AI_TARGET, STATUS3_HEAL_BLOCK, Score_Minus10 - end - -AI_CBM_GastroAcid: - if_status3 AI_TARGET, STATUS3_GASTRO_ACID, Score_Minus10 - end - -AI_CBM_AquaRing: - if_status3 AI_USER, STATUS3_AQUA_RING, Score_Minus10 - end - -AI_CBM_LuckyChant: - if_side_affecting AI_USER, SIDE_STATUS_LUCKY_CHANT, Score_Minus10 - end - -AI_CBM_Embargo: - if_status3 AI_TARGET, STATUS3_EMBARGO, Score_Minus10 - end - -AI_CBM_Gravity: - if_field_status STATUS_FIELD_GRAVITY, Score_Minus10 - end - -@ Don't use hazards if target side has no mons to switch -AI_CBM_Hazards: - count_usable_party_mons AI_TARGET - if_equal 0, Score_Minus10 - end - -AI_CBM_ToxicSpikes: - if_not_side_affecting AI_TARGET, SIDE_STATUS_TOXIC_SPIKES, AI_Ret - get_hazards_count AI_TARGET, EFFECT_TOXIC_SPIKES - if_equal 2, Score_Minus10 - goto AI_CBM_Hazards - -AI_CBM_StealthRock: - if_side_affecting AI_TARGET, SIDE_STATUS_STEALTH_ROCK, Score_Minus10 - goto AI_CBM_Hazards - -AI_CBM_StickyWeb: - if_side_affecting AI_TARGET, SIDE_STATUS_STICKY_WEB, Score_Minus10 - goto AI_CBM_Hazards - -AI_CBM_Sleep: @ 82DC2D4 - 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 - end - -AI_CBM_Explosion: @ 82DC2F7 - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_DAMP, Score_Minus10 - count_usable_party_mons AI_USER - if_not_equal 0, AI_CBM_Explosion_End - count_usable_party_mons AI_TARGET - if_not_equal 0, Score_Minus10 - goto Score_Minus1 - -AI_CBM_Explosion_End: @ 82DC31A - end - -AI_CBM_Nightmare: @ 82DC31B - if_status2 AI_TARGET, STATUS2_NIGHTMARE, Score_Minus10 - if_not_status AI_TARGET, STATUS1_SLEEP, Score_Minus8 - end - -AI_CBM_DreamEater: @ 82DC330 - if_not_status AI_TARGET, STATUS1_SLEEP, Score_Minus8 - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - end - -AI_CBM_BellyDrum: @ 82DC341 - if_hp_less_than AI_USER, 51, Score_Minus10 - -AI_CBM_AttackUp: @ 82DC348 - if_stat_level_equal AI_USER, STAT_ATK, 12, Score_Minus10 - @ Do not raise attack if has no physical moves - if_has_move_with_effect AI_USER, EFFECT_BATON_PASS, AI_Ret - if_has_no_physical_move AI_USER, Score_Minus10 - end - -AI_CBM_DefenseUp: @ 82DC351 - if_stat_level_equal AI_USER, STAT_DEF, MAX_STAT_STAGE, Score_Minus10 - end - -AI_CBM_SpeedUp: @ 82DC35A - if_stat_level_equal AI_USER, STAT_SPEED, MAX_STAT_STAGE, Score_Minus10 - end - -AI_CBM_SpAtkUp: @ 82DC363 - if_stat_level_equal AI_USER, STAT_SPATK, 12, Score_Minus10 - @ Do not raise sp. attack if has no special moves - if_has_move_with_effect AI_USER, EFFECT_BATON_PASS, AI_Ret - if_has_no_special_move AI_USER, Score_Minus10 - end - -AI_CBM_SpDefUp: @ 82DC36C - if_stat_level_equal AI_USER, STAT_SPDEF, MAX_STAT_STAGE, Score_Minus10 - end - -AI_CBM_AccUp: @ 82DC375 - if_stat_level_equal AI_USER, STAT_ACC, MAX_STAT_STAGE, Score_Minus10 - end - -AI_CBM_EvasionUp: @ 82DC37E - if_stat_level_equal AI_USER, STAT_EVASION, MAX_STAT_STAGE, Score_Minus10 - end - -AI_CBM_AttackDown: @ 82DC387 - if_stat_level_equal AI_TARGET, STAT_ATK, MIN_STAT_STAGE, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_HYPER_CUTTER, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_DefenseDown: @ 82DC39C - if_stat_level_equal AI_TARGET, STAT_DEF, 0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_BIG_PECKS, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_SpeedDown: @ 82DC3A9 - if_stat_level_equal AI_TARGET, STAT_SPEED, MIN_STAT_STAGE, Score_Minus10 - if_ability AI_TARGET, ABILITY_SPEED_BOOST, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_SpAtkDown: @ 82DC3BF - if_stat_level_equal AI_TARGET, STAT_SPATK, MIN_STAT_STAGE, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_SpDefDown: @ 82DC3CC - if_stat_level_equal AI_TARGET, STAT_SPDEF, MIN_STAT_STAGE, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_AccDown: @ 82DC3D9 - if_stat_level_equal AI_TARGET, STAT_ACC, MIN_STAT_STAGE, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_KEEN_EYE, Score_Minus10 - goto CheckIfAbilityBlocksStatChange - -AI_CBM_EvasionDown: @ 82DC3EE - if_stat_level_equal AI_TARGET, STAT_EVASION, MIN_STAT_STAGE, Score_Minus10 - -CheckIfAbilityBlocksStatChange: @ 82DC3F6 - get_ability AI_TARGET - if_equal ABILITY_CLEAR_BODY, Score_Minus10 - if_equal ABILITY_WHITE_SMOKE, Score_Minus10 - end - -AI_CBM_Haze: @ 82DC405 - if_stat_level_less_than AI_USER, STAT_ATK, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_DEF, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_SPEED, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_SPATK, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_SPDEF, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_ACC, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_less_than AI_USER, STAT_EVASION, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_ATK, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_DEF, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_SPEED, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_SPATK, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_SPDEF, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_ACC, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - if_stat_level_more_than AI_TARGET, STAT_EVASION, DEFAULT_STAT_STAGE, AI_CBM_Haze_End - goto Score_Minus10 - -AI_CBM_Haze_End: @ 82DC47A - end - -AI_CBM_Roar: @ 82DC47B - count_usable_party_mons AI_TARGET - if_equal 0, Score_Minus10 - get_ability AI_TARGET - if_equal ABILITY_SUCTION_CUPS, Score_Minus10 - end - -AI_CBM_Toxic: @ 82DC48C - 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_equal ABILITY_TOXIC_BOOST, Score_Minus10 - if_status AI_TARGET, STATUS1_ANY, Score_Minus10 - if_side_affecting AI_TARGET, SIDE_STATUS_SAFEGUARD, Score_Minus10 - end - -AI_CBM_LightScreen: @ 82DC4C5 - if_side_affecting AI_USER, SIDE_STATUS_LIGHTSCREEN, Score_Minus8 - end - -AI_CBM_OneHitKO: @ 82DC4D0 - 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: @ 82DC4E5 - get_ability AI_TARGET - if_equal ABILITY_LEVITATE, Score_Minus10 - -AI_CBM_HighRiskForDamage: @ 82DC4ED - 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: @ 82DC506 - end - -AI_CBM_Mist: @ 82DC507 - if_side_affecting AI_USER, SIDE_STATUS_MIST, Score_Minus8 - end - -AI_CBM_FocusEnergy: @ 82DC512 - if_status2 AI_USER, STATUS2_FOCUS_ENERGY, Score_Minus10 - end - -AI_CBM_Confuse: @ 82DC51D - 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 - end - -AI_CBM_Reflect: @ 82DC53A - if_side_affecting AI_USER, SIDE_STATUS_REFLECT, Score_Minus8 - end - -AI_CBM_Paralyze: @ 82DC545 - 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 - end - -AI_CBM_Substitute: @ 82DC568 - if_status2 AI_USER, STATUS2_SUBSTITUTE, Score_Minus8 - if_hp_less_than AI_USER, 26, Score_Minus10 - end - -AI_CBM_LeechSeed: @ 82DC57A - if_status3 AI_TARGET, STATUS3_LEECHSEED, Score_Minus10 - if_type AI_TARGET, TYPE_GRASS, Score_Minus10 - end - -AI_CBM_Disable: @ 82DC595 - if_any_move_disabled AI_TARGET, Score_Minus8 - if_no_move_used AI_TARGET, Score_Minus8 - end - -AI_CBM_Encore: @ 82DC59D - if_any_move_encored AI_TARGET, Score_Minus8 - if_no_move_used AI_TARGET, Score_Minus8 - end - -AI_CBM_DamageDuringSleep: @ 82DC5A5 - if_not_status AI_USER, STATUS1_SLEEP, Score_Minus8 - end - -AI_CBM_CantEscape: @ 82DC5B0 - if_status2 AI_TARGET, STATUS2_ESCAPE_PREVENTION, Score_Minus10 - end - -AI_CBM_Curse: @ 82DC5BB - if_stat_level_equal AI_USER, STAT_ATK, MAX_STAT_STAGE, Score_Minus10 - if_stat_level_equal AI_USER, STAT_DEF, MAX_STAT_STAGE, Score_Minus8 - end - -AI_CBM_Spikes: @ 82DC5CC - call AI_CBM_Hazards - if_not_side_affecting AI_TARGET, SIDE_STATUS_SPIKES, AI_Ret - get_hazards_count AI_TARGET, EFFECT_SPIKES - if_equal 3, Score_Minus10 - end - -AI_CBM_Foresight: @ 82DC5D7 - if_status2 AI_TARGET, STATUS2_FORESIGHT, Score_Minus10 - if_status3 AI_TARGET, STATUS3_MIRACLE_EYED, Score_Minus10 - end - -AI_CBM_PerishSong: @ 82DC5E2 - if_status3 AI_TARGET, STATUS3_PERISH_SONG, Score_Minus10 - end - -AI_CBM_Sandstorm: @ 82DC5ED - get_weather - if_equal AI_WEATHER_SANDSTORM, Score_Minus8 - end - -AI_IsOppositeGender: - get_ability AI_TARGET - if_equal ABILITY_OBLIVIOUS, Score_Minus10 - get_gender AI_USER - if_equal 0, AI_IsOppositeGenderFemale - if_equal 254, AI_IsOppositeGenderMale - goto Score_Minus10 -AI_IsOppositeGenderFemale: @ 82DC61A - get_gender AI_TARGET - if_equal 254, AI_CBM_Attract_End - goto Score_Minus10 -AI_IsOppositeGenderMale: @ 82DC627 - get_gender AI_TARGET - if_equal 0, AI_CBM_Attract_End - goto Score_Minus10 - end - -AI_CBM_Captivate: - call AI_IsOppositeGender - goto AI_CBM_SpAtkDown - -AI_CBM_Attract: @ 82DC5F5 - if_status2 AI_TARGET, STATUS2_INFATUATION, Score_Minus10 - call AI_IsOppositeGender - end - -AI_CBM_Attract_End: @ 82DC634 - end - -AI_CBM_Safeguard: @ 82DC635 - if_side_affecting AI_USER, SIDE_STATUS_SAFEGUARD, Score_Minus8 - end - -AI_CBM_Memento: @ 82DC640 - if_stat_level_equal AI_TARGET, STAT_ATK, MIN_STAT_STAGE, Score_Minus10 - if_stat_level_equal AI_TARGET, STAT_SPATK, MIN_STAT_STAGE, Score_Minus8 - -AI_CBM_BatonPass: @ 82DC650 - count_usable_party_mons AI_USER - if_equal 0, Score_Minus10 - end - -AI_CBM_RainDance: @ 82DC659 - get_weather - if_equal AI_WEATHER_RAIN, Score_Minus8 - end - -AI_CBM_SunnyDay: @ 82DC661 - get_weather - if_equal AI_WEATHER_SUN, Score_Minus8 - end - -AI_CBM_FutureSight: @ 82DC669 - if_side_affecting AI_TARGET, SIDE_STATUS_FUTUREATTACK, Score_Minus12 - if_side_affecting AI_USER, SIDE_STATUS_FUTUREATTACK, Score_Minus12 - score +5 - end - -AI_CBM_FakeOut: @ 82DC680 - is_first_turn_for AI_USER - if_equal 0, Score_Minus10 - end - -AI_CBM_Stockpile: @ 82DC689 - get_stockpile_count AI_USER - if_equal 3, Score_Minus10 - end - -AI_CBM_SpitUpAndSwallow: @ 82DC692 - if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 - get_stockpile_count AI_USER - if_equal 0, Score_Minus10 - end - -AI_CBM_Hail: @ 82DC6A1 - get_weather - if_equal AI_WEATHER_HAIL, Score_Minus8 - end - -AI_CBM_Torment: @ 82DC6A9 - if_status2 AI_TARGET, STATUS2_TORMENT, Score_Minus10 - end - -AI_CBM_WillOWisp: @ 82DC6B4 - get_ability AI_TARGET - if_equal ABILITY_WATER_VEIL, Score_Minus10 - if_equal ABILITY_FLARE_BOOST, Score_Minus10 - if_equal ABILITY_FLASH_FIRE, Score_Minus10 - if_status AI_TARGET, STATUS1_ANY, Score_Minus10 - if_type AI_TARGET, TYPE_FIRE, Score_Minus10 - if_side_affecting AI_TARGET, SIDE_STATUS_SAFEGUARD, Score_Minus10 - end - -AI_CBM_HelpingHand: @ 82DC6E3 - if_not_double_battle Score_Minus10 - if_battler_absent AI_USER_PARTNER, Score_Minus10 - end - -AI_CBM_TrickAndKnockOff: @ 82DC6EB - get_ability AI_TARGET - if_equal ABILITY_STICKY_HOLD, Score_Minus10 - end - -AI_CBM_Ingrain: @ 82DC6F4 - if_status3 AI_USER, STATUS3_ROOTED, Score_Minus10 - end - -AI_CBM_Recycle: @ 82DC6FF - get_used_held_item AI_USER - if_equal 0, Score_Minus10 - end - -AI_CBM_Imprison: @ 82DC708 - if_status3 AI_USER, STATUS3_IMPRISONED_OTHERS, Score_Minus10 - end - -AI_CBM_Refresh: @ 82DC713 - if_not_status AI_USER, STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON, Score_Minus10 - end - -AI_CBM_MudSport: @ 82DC71E - if_field_status STATUS_FIELD_MUDSPORT, Score_Minus10 - end - -AI_CBM_Tickle: @ 82DC729 - if_stat_level_equal AI_TARGET, STAT_ATK, MIN_STAT_STAGE, Score_Minus10 - if_stat_level_equal AI_TARGET, STAT_DEF, MIN_STAT_STAGE, Score_Minus8 - end - -AI_CBM_CosmicPower: @ 82DC73A - if_stat_level_equal AI_USER, STAT_DEF, MAX_STAT_STAGE, Score_Minus10 - if_stat_level_equal AI_USER, STAT_SPDEF, MAX_STAT_STAGE, Score_Minus8 - end - -AI_CBM_BulkUp: @ 82DC74B - if_stat_level_equal AI_USER, STAT_ATK, MAX_STAT_STAGE, Score_Minus10 - if_stat_level_equal AI_USER, STAT_DEF, MAX_STAT_STAGE, Score_Minus8 - end - -AI_CBM_WaterSport: @ 82DC75C - if_field_status STATUS_FIELD_WATERSPORT, Score_Minus10 - end - -AI_CBM_CalmMind: @ 82DC767 - if_stat_level_equal AI_USER, STAT_SPATK, MAX_STAT_STAGE, Score_Minus10 - if_stat_level_equal AI_USER, STAT_SPDEF, MAX_STAT_STAGE, Score_Minus8 - end - -AI_CBM_DragonDance: @ 82DC778 - if_stat_level_equal AI_USER, STAT_ATK, MAX_STAT_STAGE, Score_Minus10 - if_stat_level_equal AI_USER, STAT_SPEED, MAX_STAT_STAGE, 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_Minus30: - score -30 - end - -Score_Plus1: - score +1 - end - -Score_Plus2: - score +2 - end - -Score_Plus3: - score +3 - end - -Score_Plus5: - score +5 - end - -Score_Plus10: - score +10 - end - -@ omae wa mou shindeiru -@ Basically a scenario where the players mon is faster, able to hit and able to OHKO -@ In which, it would be best to use a priority move to deal any damage -AI_CheckIfAlreadyDead: - if_status2 AI_TARGET, STATUS2_RECHARGE | STATUS2_BIDE, AI_Ret - if_ai_can_go_down AI_CheckIfAlreadyDeadPriorities - end -AI_CheckIfAlreadyDeadPriorities: - if_target_faster Score_Minus1 - if_random_less_than 126, AI_Ret - score +1 - end - -@ The purpose is to use a move effect that hits the hardest or similar -AI_CV_DmgMove: - get_considered_move_power - if_equal 0, AI_Ret - get_how_powerful_move_is - if_equal MOVE_POWER_WEAK, Score_Minus1 - end - -@ If move deals shit damage, and there are other mons to switch in, use support moves instead -AI_WeakDmg: - get_considered_move_power - if_equal 0, AI_Ret - if_has_no_move_with_split AI_USER, SPLIT_STATUS, AI_Ret - get_curr_dmg_hp_percent - if_more_than 30, AI_Ret - if_more_than 20, Score_Minus1 - get_how_powerful_move_is - if_equal MOVE_POWER_BEST, Score_Minus2 - score -3 - end - -AI_DiscourageMagicGuard: - if_no_ability AI_TARGET, ABILITY_MAGIC_GUARD, AI_DiscourageMagicGuardEnd - if_effect EFFECT_POISON, Score_Minus5 - if_effect EFFECT_WILL_O_WISP, Score_Minus5 - if_effect EFFECT_TOXIC, Score_Minus5 - if_effect EFFECT_LEECH_SEED, Score_Minus5 - if_no_type AI_TARGET, TYPE_GHOST, AI_DiscourageMagicGuardEnd - if_effect EFFECT_CURSE, Score_Minus5 -AI_DiscourageMagicGuardEnd: - end - -AI_CheckViability: - if_target_is_ally AI_Ret - call_if_always_hit AI_CV_AlwaysHit - call_if_move_flag FLAG_HIGH_CRIT, AI_CV_HighCrit - call AI_CheckIfAlreadyDead - call AI_CV_DmgMove - call AI_WeakDmg - call AI_DiscourageMagicGuard - if_effect EFFECT_HIT, AI_CV_Hit - 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_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_SOFTBOILED, AI_CV_Heal - if_effect EFFECT_SWALLOW, AI_CV_Heal - if_effect EFFECT_ROOST, 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_SUPER_FANG, AI_CV_SuperFang - if_effect EFFECT_TRAP, AI_CV_Trap - if_effect EFFECT_CONFUSE, AI_CV_Confuse - if_effect EFFECT_FOCUS_ENERGY, AI_CV_FocusEnergy - 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_AURORA_VEIL, AI_CV_AuroraVeil - if_effect EFFECT_POISON, AI_CV_Poison - if_effect EFFECT_TOXIC_THREAD, AI_CV_ToxicThread - if_effect EFFECT_PARALYZE, AI_CV_Paralyze - if_effect EFFECT_SWAGGER, AI_CV_Swagger - if_effect EFFECT_SPEED_DOWN_HIT, AI_CV_SpeedDownFromChance - if_effect EFFECT_TWO_TURNS_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_LeechSeed - 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_LOCK_ON, AI_CV_LockOn - if_effect EFFECT_SLEEP_TALK, AI_CV_SleepTalk - if_effect EFFECT_SNORE, 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_SHORE_UP, AI_CV_Heal - 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_SOLARBEAM, AI_CV_ChargeUpMove - if_effect EFFECT_GEOMANCY, AI_CV_Geomancy - 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_HAIL, AI_CV_Sandstorm - if_effect EFFECT_SANDSTORM, AI_CV_Sandstorm - 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_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_WATER_SPORT, AI_CV_WaterSport - if_effect EFFECT_CALM_MIND, AI_CV_SpDefUp - if_effect EFFECT_DRAGON_DANCE, AI_CV_DragonDance - if_effect EFFECT_POWDER, AI_CV_Powder - if_effect EFFECT_MISTY_TERRAIN, AI_CV_MistyTerrain - if_effect EFFECT_GRASSY_TERRAIN, AI_CV_GrassyTerrain - if_effect EFFECT_ELECTRIC_TERRAIN, AI_CV_ElectricTerrain - if_effect EFFECT_PSYCHIC_TERRAIN, AI_CV_PsychicTerrain - if_effect EFFECT_STEALTH_ROCK, AI_CV_Hazards - if_effect EFFECT_SPIKES, AI_CV_Hazards - if_effect EFFECT_STICKY_WEB, AI_CV_Hazards - if_effect EFFECT_TOXIC_SPIKES, AI_CV_Hazards - if_effect EFFECT_PERISH_SONG, AI_CV_PerishSong - end - -AI_CV_PerishSong: - get_ability AI_USER - if_equal ABILITY_ARENA_TRAP, AI_CV_PerishSong_ArenaTrap - if_equal ABILITY_MAGNET_PULL, AI_CV_PerishSong_MagnetPull - if_equal ABILITY_SHADOW_TAG, AI_CV_PerishSong_ShadowTag -AI_CV_PerishSongCheckTrap: - if_status2 AI_TARGET, STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION, Score_Plus3 - @ If has a move that can trap, use it first, then use Perish Song - if_double_battle AI_Ret - if_has_move_with_effect AI_USER, EFFECT_TRAP, Score_Minus5 - if_has_move_with_effect AI_USER, EFFECT_MEAN_LOOK, Score_Minus5 - end -AI_CV_PerishSong_ArenaTrap: - if_grounded AI_TARGET, Score_Plus2 - goto AI_CV_PerishSongCheckTrap -AI_CV_PerishSong_MagnetPull: - if_type AI_TARGET, TYPE_STEEL, Score_Plus2 - goto AI_CV_PerishSongCheckTrap -AI_CV_PerishSong_ShadowTag: - if_no_ability AI_TARGET, ABILITY_SHADOW_TAG, Score_Plus2 - goto AI_CV_PerishSongCheckTrap - -AI_CV_Hazards: - if_ability AI_TARGET, ABILITY_MAGIC_BOUNCE, AI_CV_HzardsEnd - is_first_turn_for AI_USER - if_equal 0, AI_CV_HzardsEnd - score +2 -AI_CV_HzardsEnd: - end -AI_CV_StealthRock2: - score -2 - goto AI_CV_HzardsEnd - -AI_CV_MistyTerrain: - call AI_CV_TerrainExpander - end - -AI_CV_GrassyTerrain: - call AI_CV_TerrainExpander - end - -AI_CV_ElectricTerrain: - call AI_CV_TerrainExpander - end - -AI_CV_PsychicTerrain: - call AI_CV_TerrainExpander - end - -AI_CV_TerrainExpander: - get_hold_effect AI_USER - if_equal HOLD_EFFECT_TERRAIN_EXTENDER, Score_Plus2 - end - -AI_CV_Powder: - if_type AI_TARGET, TYPE_FIRE, AI_CV_Powder2 - if_has_move_with_type AI_TARGET, TYPE_FIRE, AI_CV_Powder2 - score -2 - end -AI_CV_Powder2: - is_first_turn_for AI_TARGET - if_equal 0, AI_CV_Powder3 - if_random_less_than 100, AI_CV_Powder3 - score +1 -AI_CV_Powder3: - if_type AI_USER, TYPE_BUG, AI_CV_Powder4 - if_type AI_USER, TYPE_GRASS, AI_CV_Powder4 - if_no_type AI_USER, TYPE_STEEL, AI_CV_Powder5 -AI_CV_Powder4: - score +1 -AI_CV_Powder5: - get_last_used_bank_move AI_USER - if_equal_u32 MOVE_POWDER, AI_CV_Powder6 - if_random_less_than 150, Score_Minus1 - if_random_less_than 200, AI_Ret - score +2 - end -AI_CV_Powder6: - if_random_less_than 136, Score_Minus2 - score +1 - end - -AI_CV_Hit: - end - -AI_CV_Sleep: @ 82DCA92 - 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: @ 82DCAA5 - if_random_less_than 128, AI_CV_Sleep_End - score +1 - -AI_CV_Sleep_End: @ 82DCAAD - end - -AI_CV_Absorb: @ 82DCAAE - 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: @ 82DCABF - if_random_less_than 50, AI_CV_Absorb_End - score -3 - -AI_CV_Absorb_End: @ 82DCAC7 - end - -AI_CV_SelfKO: @ 82DCAC8 - 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: @ 82DCAE2 - 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: @ 82DCAFA - 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: @ 82DCB09 - 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: @ 82DCB1D - if_random_less_than 50, AI_CV_SelfKO_End - score -1 - -AI_CV_SelfKO_End: @ 82DCB25 - end - -AI_CV_DreamEater: @ 82DCB26 - 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: @ 82DCB37 - score -1 - -AI_CV_DreamEater_End: @ 82DCB39 - end - -AI_CV_MirrorMove: @ 82DCB3A - if_target_faster AI_CV_MirrorMove2 - get_last_used_bank_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: @ 82DCB58 - get_last_used_bank_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: @ 82DCB6B - end - -.align 1 -AI_CV_MirrorMove_EncouragedMovesToMirror: @ 82DCB6C - .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: @ 82DCBBC - if_physical_moves_unusable AI_USER, AI_TARGET, Score_Minus8 - 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: @ 82DCBD1 - if_hp_not_equal AI_USER, 100, AI_CV_AttackUp3 - if_random_less_than 128, AI_CV_AttackUp3 - score +2 - -AI_CV_AttackUp3: @ 82DCBE0 - 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: @ 82DCBF4 - score -2 - -AI_CV_AttackUp_End: @ 82DCBF6 - end - -AI_CV_DefenseUp: @ 82DCBF7 - 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: @ 82DCC0C - if_hp_not_equal AI_USER, 100, AI_CV_DefenseUp3 - if_random_less_than 128, AI_CV_DefenseUp3 - score +2 - -AI_CV_DefenseUp3: @ 82DCC1B - if_hp_less_than AI_USER, 70, AI_CV_DefenseUp4 - if_random_less_than 200, AI_CV_DefenseUp_End - -AI_CV_DefenseUp4: @ 82DCC28 - if_hp_less_than AI_USER, 40, AI_CV_DefenseUp_ScoreDown2 - get_last_used_bank_move AI_TARGET - get_move_power_from_result - if_equal 0, AI_CV_DefenseUp5 - get_last_used_bank_move AI_TARGET - get_move_split_from_result - if_not_equal SPLIT_PHYSICAL, AI_CV_DefenseUp_ScoreDown2 - if_random_less_than 60, AI_CV_DefenseUp_End - -AI_CV_DefenseUp5: @ 82DCC4A - if_random_less_than 60, AI_CV_DefenseUp_End - -AI_CV_DefenseUp_ScoreDown2: @ 82DCC50 - score -2 - -AI_CV_DefenseUp_End: @ 82DCC52 - end - -AI_CV_SpeedUp: @ 82DCC5D - if_target_faster AI_CV_SpeedUp2 - score -3 - goto AI_CV_SpeedUp_End - -AI_CV_SpeedUp2: @ 82DCC6A - if_random_less_than 70, AI_CV_SpeedUp_End - score +3 - -AI_CV_SpeedUp_End: @ 82DCC72 - end - -AI_CV_SpAtkUp: @ 82DCC73 - 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: @ 82DCC88 - if_hp_not_equal AI_USER, 100, AI_CV_SpAtkUp3 - if_random_less_than 128, AI_CV_SpAtkUp3 - score +2 - -AI_CV_SpAtkUp3: @ 82DCC97 - 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: @ 82DCCAB - score -2 - -AI_CV_SpAtkUp_End: @ 82DCCAD - end - -AI_CV_SpDefUp: @ 82DCCAE - 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: @ 82DCCC3 - if_hp_not_equal AI_USER, 100, AI_CV_SpDefUp3 - if_random_less_than 128, AI_CV_SpDefUp3 - score +2 - -AI_CV_SpDefUp3: @ 82DCCD2 - if_hp_less_than AI_USER, 70, AI_CV_SpDefUp4 - if_random_less_than 200, AI_CV_SpDefUp_End - -AI_CV_SpDefUp4: @ 82DCCDF - if_hp_less_than AI_USER, 40, AI_CV_SpDefUp_ScoreDown2 - get_last_used_bank_move AI_TARGET - get_move_power_from_result - if_equal 0, AI_CV_SpDefUp5 - get_last_used_bank_move AI_TARGET - get_move_split_from_result - if_not_equal SPLIT_SPECIAL, AI_CV_SpDefUp_ScoreDown2 - if_random_less_than 60, AI_CV_SpDefUp_End - -AI_CV_SpDefUp5: @ 82DCD01 - if_random_less_than 60, AI_CV_SpDefUp_End - -AI_CV_SpDefUp_ScoreDown2: @ 82DCD07 - score -2 - -AI_CV_SpDefUp_End: @ 82DCD09 - end - -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, DEFAULT_STAT_STAGE, 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: @ 82DCDF8 - if_stat_level_equal AI_TARGET, STAT_ATK, DEFAULT_STAT_STAGE, AI_CV_AttackDown3 - score -1 - if_hp_more_than AI_USER, 90, AI_CV_AttackDown2 - score -1 - -AI_CV_AttackDown2: @ 82DCE0B - 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: @ 82DCE1B - if_hp_more_than AI_TARGET, 70, AI_CV_AttackDown4 - score -2 - -AI_CV_AttackDown4: @ 82DCE24 - get_target_type1 - if_in_bytes AI_CV_AttackDown_UnknownTypeList, AI_CV_AttackDown_End - get_target_type2 - if_in_bytes AI_CV_AttackDown_UnknownTypeList, AI_CV_AttackDown_End - if_random_less_than 50, AI_CV_AttackDown_End - score -2 - -AI_CV_AttackDown_End: @ 82DCE42 - end - -AI_CV_AttackDown_UnknownTypeList: - .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: @ 82DCE6B - 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: @ 82DCE81 - if_target_faster AI_CV_SpeedDown2 - score -3 - goto AI_CV_SpeedDown_End -AI_CV_SpeedDown2: @ 82DCE8E - if_random_less_than 70, AI_CV_SpeedDown_End - score +2 -AI_CV_SpeedDown_End: @ 82DCE96 - end - -AI_CV_SpAtkDown: - if_stat_level_equal AI_TARGET, STAT_ATK, DEFAULT_STAT_STAGE, 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: @ 82DCEE1 - end - -AI_CV_SpAtkDown_SpecialTypeList: @ 82DCEE2 - .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 -1 - -AI_CV_SpDefDown: @ 82DCEEB - 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: @ 82DCEFA - if_random_less_than 50, AI_CV_SpDefDown3 - score -2 - -AI_CV_SpDefDown3: @ 82DCF02 - if_hp_more_than AI_TARGET, 70, AI_CV_SpDefDown_End - score -2 - -AI_CV_SpDefDown_End: @ 82DCF0B - end - -AI_CV_AccuracyDown: @ 82DCF0C - 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, DEFAULT_STAT_STAGE, 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_4 - score -2 -AI_CV_EvasionDown_4: - if_stat_level_less_than AI_USER, STAT_ACC, 6, AI_CV_EvasionDown_5 - if_stat_level_less_than AI_TARGET, STAT_EVASION, 7, AI_CV_EvasionDown_6 - if_ability AI_USER, ABILITY_NO_GUARD, AI_CV_EvasionDown_6 -AI_CV_EvasionDown_End: - end -AI_CV_EvasionDown_5: - score +1 - goto AI_CV_EvasionDown_End -AI_CV_EvasionDown_6: - score -2 - goto AI_CV_EvasionDown_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 - -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 - -EncouragePsnVenoshock: - if_doesnt_have_move_with_effect AI_USER, EFFECT_VENOSHOCK, EncouragePsnVenoshockEnd - score +1 - if_random_less_than 128, EncouragePsnVenoshockEnd - score +1 -EncouragePsnVenoshockEnd: - end - -AI_CV_Toxic: - call EncouragePsnVenoshock -AI_CV_LeechSeed: - 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: - call EncourageLightClay - 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 -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: - if_status3 AI_TARGET, STATUS3_ALWAYS_HITS, Score_Plus5 - 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_status2 AI_TARGET, STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION, AI_CV_TrapEnd - if_status3 AI_TARGET, STATUS3_PERISH_SONG, AI_CV_Trap5 - if_doesnt_have_move_with_effect AI_USER, EFFECT_PERISH_SONG, AI_CV_Trap1 - score +3 -AI_CV_Trap1: - if_status AI_TARGET, STATUS1_TOXIC_POISON, AI_CV_Trap2 - if_status2 AI_TARGET, STATUS2_CURSED | STATUS2_INFATUATION, AI_CV_Trap2 - goto AI_CV_TrapItem -AI_CV_Trap5: - score +2 - goto AI_CV_TrapItem -AI_CV_Trap2: - if_random_less_than 128, AI_CV_TrapItem - score +1 -AI_CV_TrapItem: - get_considered_move_power - if_equal 0, AI_CV_TrapEnd - if_status2 AI_TARGET, STATUS2_WRAPPED, AI_CV_TrapEnd - get_hold_effect AI_USER - if_equal HOLD_EFFECT_GRIP_CLAW AI_CV_Trap4 - if_equal HOLD_EFFECT_BINDING_BAND AI_CV_Trap4 - goto AI_CV_TrapEnd -AI_CV_Trap4: - score +2 -AI_CV_TrapEnd: - 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 - -AI_CV_FocusEnergy: - if_has_move_with_flag AI_USER, FLAG_HIGH_CRIT, AI_CV_FocusEnergy2 -AI_CV_FocusEnergy3: - get_hold_effect AI_USER - if_not_equal HOLD_EFFECT_SCOPE_LENS, AI_CV_FocusEnergyEnd - score +1 -AI_CV_FocusEnergyEnd: - end -AI_CV_FocusEnergy2: - score +1 - goto AI_CV_FocusEnergy3 - -AI_CV_Swagger: - if_doesnt_have_move_with_effect AI_USER, EFFECT_FOUL_PLAY, AI_CV_Swagger2 - score +1 -AI_CV_Swagger2: - 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 - -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 - -EncourageLightClay: - get_hold_effect AI_USER - if_not_equal HOLD_EFFECT_LIGHT_CLAY, EncourageLightClayEnd - score +1 - if_random_less_than 111, EncourageLightClayEnd - score +1 -EncourageLightClayEnd: - end - -AI_CV_AuroraVeil: - call EncourageLightClay - end - -AI_CV_Reflect: - call EncourageLightClay - 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_ToxicThread: - if_status AI_TARGET, STATUS1_ANY, AI_CV_ToxicThreadSpd - call EncouragePsnVenoshock -AI_CV_ToxicThreadSpd: - if_target_faster AI_CV_ToxicThread2 - if_not_status AI_TARGET, STATUS1_ANY, AI_CV_ToxicThread3 - score -1 - goto AI_CV_ToxicThread3 -AI_CV_ToxicThread2: - score +1 -AI_CV_ToxicThread3: - goto AI_CV_Poison2 - -AI_CV_Poison: - call EncouragePsnVenoshock -AI_CV_Poison2: - 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_not_status2 AI_TARGET, STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION, AI_CV_Substitute1 - if_status3 AI_TARGET, STATUS3_PERISH_SONG, AI_CV_SubstitutePlus3Continue - if_status AI_TARGET, STATUS1_BURN | STATUS1_PSN_ANY, AI_CV_SubstitutePlus1Continue - goto AI_CV_Substitute1 -AI_CV_SubstitutePlus1Continue: - score +1 - goto AI_CV_Substitute1 -AI_CV_SubstitutePlus3Continue: - score +3 -AI_CV_Substitute1: - 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_bank_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_bank_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 - get_last_used_bank_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_bank_move AI_TARGET - get_move_split_from_result - if_not_equal SPLIT_PHYSICAL, 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: - if_has_no_physical_move AI_TARGET, AI_CV_Counter_ScoreDown1 - if_random_less_than 50, AI_CV_Counter_End - -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_Encore: - if_any_move_disabled AI_TARGET, AI_CV_Encore2 - if_target_faster AI_CV_Encore_ScoreDown2 - get_last_used_bank_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: - .byte -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_EncourageIfHasOHKO: - if_level_cond 1, AI_EncourageIfHasOHKORet - if_has_move_with_effect AI_USER, EFFECT_OHKO, Score_Plus3 -AI_EncourageIfHasOHKORet: - end - -AI_EncourageIfHasLowAccuracyMove: - if_ability AI_USER, ABILITY_COMPOUND_EYES, AI_EncourageIfHasVeryLowAccuracyMove - get_hold_effect AI_USER - if_equal HOLD_EFFECT_WIDE_LENS, AI_EncourageIfHasVeryLowAccuracyMove - if_equal HOLD_EFFECT_ZOOM_LENS, AI_EncourageIfHasVeryLowAccuracyMove - if_has_move_with_accuracy_lt AI_USER, 86, Score_Plus3 - if_has_move_with_accuracy_lt AI_USER, 91, Score_Plus1 - goto Score_Minus1 -AI_EncourageIfHasVeryLowAccuracyMove: - if_has_move_with_accuracy_lt AI_USER, 81, Score_Plus3 - if_has_move_with_accuracy_lt AI_USER, 86, Score_Plus1 - goto Score_Minus1 - -AI_CV_LockOn: - call AI_EncourageIfHasOHKO - call AI_EncourageIfHasLowAccuracyMove -AI_CV_LockOn2: - if_random_less_than 128, AI_CV_LockOn_End - score +1 - -AI_CV_LockOn_End: - end - -AI_CV_SleepTalk: - is_wakeup_turn AI_USER - if_equal 1, Score_Minus5 - if_status AI_USER, STATUS1_SLEEP, Score_Plus10 - score -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_move MOVE_HEAL_BELL AI_CV_HealBell2 -AI_CV_HealBellEnd: - end -@ Don't use Heal Bell to heal a partner that has Soundproof -AI_CV_HealBell2: - if_status AI_USER, STATUS1_ANY, AI_CV_HealBellEnd - if_not_status AI_USER_PARTNER, STATUS1_ANY, AI_CV_HealBellEnd - if_ability AI_USER_PARTNER, ABILITY_SOUNDPROOF, Score_Minus3 - goto AI_CV_HealBellEnd - -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: - if_type AI_USER, TYPE_GHOST, AI_CV_CurseGhost - if_stat_level_more_than AI_USER, STAT_DEF, 9, AI_CV_Curse2 - if_random_less_than 128, AI_CV_Curse2 - score +1 -AI_CV_Curse2: - if_stat_level_more_than AI_USER, STAT_ATK, 9, AI_CV_Curse3 - 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_Curse4 - if_random_less_than 98, AI_CV_Curse4 - score +1 -AI_CV_Curse4: - if_stat_level_more_than AI_USER, STAT_ATK, 6, AI_CV_Curse5 - if_random_less_than 99, AI_CV_Curse5 - score +1 -AI_CV_Curse5: - get_hold_effect AI_USER - if_not_equal HOLD_EFFECT_RESTORE_STATS, AI_CV_Curse_End - score +2 - goto AI_CV_Curse_End -AI_CV_CurseGhost: - 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_PSN_ANY | STATUS1_BURN, AI_CV_ProtectUserStatused - if_status2 AI_USER, STATUS2_CURSED | STATUS2_INFATUATION, AI_CV_ProtectUserStatused - if_status3 AI_USER, STATUS3_PERISH_SONG | STATUS3_LEECHSEED | STATUS3_YAWN, AI_CV_ProtectUserStatused - 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 | STATUS2_INFATUATION, AI_CV_Protect_ScoreUp2 - if_status3 AI_TARGET, STATUS3_PERISH_SONG | STATUS3_LEECHSEED | STATUS3_YAWN, AI_CV_Protect_ScoreUp2 - get_last_used_bank_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 - 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_ProtectUserStatused: - score -1 - if_double_battle AI_CV_Protect4 - score -1 - goto AI_CV_Protect4 -AI_CV_Protect3: - get_last_used_bank_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: - if_has_move_with_type AI_USER, TYPE_NORMAL, AI_CV_ForesightGhost - if_has_move_with_type AI_USER, TYPE_FIGHTING, AI_CV_ForesightGhost - goto AI_CV_ForesightEvs -AI_CV_ForesightGhost: - if_type AI_USER, TYPE_GHOST, AI_CV_Foresight2 -AI_CV_ForesightEvs: - if_stat_level_more_than AI_USER, STAT_EVASION, 8, AI_CV_Foresight3 - score -3 - 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: - get_protect_count AI_USER - if_more_than 1, AI_CV_Endure2 - if_hp_less_than AI_USER, 8, AI_CV_Endure2 - if_hp_less_than AI_USER, 14, AI_CV_Endure4 - if_hp_less_than AI_USER, 35, AI_CV_Endure3 - if_doesnt_have_move_with_effect AI_USER, EFFECT_FLAIL, AI_CV_Endure2 - score +1 - goto AI_CV_Endure_End -AI_CV_Endure2: - score -3 - goto AI_CV_Endure_End -AI_CV_Endure4: - score -1 - goto AI_CV_Endure_End -AI_CV_Endure3: - if_has_move_with_effect AI_USER, EFFECT_FLAIL, Score_Plus2 - 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_Last - goto AI_CV_BatonPass4 -AI_CV_BatonPass3: - if_hp_more_than AI_USER, 70, AI_CV_BatonPass_Last -AI_CV_BatonPass4: - if_random_less_than 80, AI_CV_BatonPass_Last - score +2 - goto AI_CV_BatonPass_Last -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_ai_can_go_down AI_CV_BatonPass4 - if_hp_more_than AI_USER, 60, AI_CV_BatonPass_ScoreDown2 - goto AI_CV_BatonPass_Last -AI_CV_BatonPass8: - if_ai_can_go_down AI_CV_BatonPass_ScoreDown2 - if_hp_less_than AI_USER, 70, AI_CV_BatonPass_Last - goto AI_CV_BatonPass_ScoreDown2 -AI_CV_BatonPass9: - if_stat_level_more_than AI_USER, STAT_ATK, 6, AI_CV_BatonPass10 - if_stat_level_more_than AI_USER, STAT_DEF, 6, AI_CV_BatonPass10 - if_stat_level_more_than AI_USER, STAT_SPATK, 6, AI_CV_BatonPass10 - if_stat_level_more_than AI_USER, STAT_SPDEF, 6, AI_CV_BatonPass10 - if_stat_level_more_than AI_USER, STAT_EVASION, 6, AI_CV_BatonPass10 - goto AI_CV_BatonPass_ScoreDown2 -AI_CV_BatonPass10: - if_target_faster AI_CV_BatonPass11 - if_ai_can_go_down AI_CV_BatonPass4 - if_hp_more_than AI_USER, 60, AI_CV_BatonPass_ScoreDown2 - goto AI_CV_BatonPass_Last -AI_CV_BatonPass11: - if_ai_can_go_down AI_CV_BatonPass_ScoreDown2 - if_hp_less_than AI_USER, 70, AI_CV_BatonPass_Last - goto AI_CV_BatonPass_ScoreDown2 -AI_CV_BatonPass_ScoreDown2: - score -2 - end -AI_CV_BatonPass_Last: - get_best_dmg_hp_percent - if_less_than 10, Score_Plus2 - if_less_than 20, Score_Plus1 -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: - get_weather - if_equal AI_WEATHER_RAIN, AI_CV_RainDance_End - if_user_faster AI_CV_RainDance2 - get_ability AI_USER - if_equal ABILITY_SWIFT_SWIM, AI_CV_RainDance3 - get_ability AI_USER_PARTNER - 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 - if_ability AI_USER, ABILITY_RAIN_DISH, AI_CV_RainDance3 - if_ability AI_USER_PARTNER, ABILITY_RAIN_DISH, AI_CV_RainDance3 - if_ability AI_USER, ABILITY_HYDRATION, AI_CV_Hydration - if_no_ability AI_USER_PARTNER, ABILITY_HYDRATION, AI_CV_RainDance_Rock -AI_CV_Hydration: - if_status AI_USER, STATUS1_ANY, AI_CV_RainDance3 - if_status AI_USER_PARTNER, STATUS1_ANY, AI_CV_RainDance3 - goto AI_CV_RainDance_Rock -AI_CV_RainDance3: - score +1 - goto AI_CV_RainDance_Rock -AI_CV_RainDance_ScoreDown1: - score -1 -AI_CV_RainDance_Rock: - get_hold_effect AI_USER - if_not_equal HOLD_EFFECT_DAMP_ROCK, AI_CV_RainDance_Opponent - score +2 -AI_CV_RainDance_Opponent: - if_has_move_with_type AI_TARGET, TYPE_FIRE, AI_CV_RainDance_OpponentPlus - if_no_type AI_TARGET, TYPE_FIRE, AI_CV_RainDance_End -AI_CV_RainDance_OpponentPlus: - score +1 -AI_CV_RainDance_End: - end - -AI_CV_SunnyDay: - get_weather - if_equal AI_WEATHER_SUN, AI_CV_SunnyDay_End - 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_Rock -AI_CV_SunnyDay2: - score +1 - goto AI_CV_SunnyDay_Rock -AI_CV_SunnyDay_ScoreDown1: - score -1 -AI_CV_SunnyDay_Rock: - get_hold_effect AI_USER - if_not_equal HOLD_EFFECT_HEAT_ROCK, AI_CV_SunnyDay_Moves - score +2 -AI_CV_SunnyDay_Moves: - if_has_move_with_effect AI_USER, EFFECT_SOLARBEAM, AI_CV_SunnyDay_MovesPlus - if_has_move_with_effect AI_USER, EFFECT_SYNTHESIS, AI_CV_SunnyDay_MovesPlus - if_has_move_with_effect AI_USER_PARTNER, EFFECT_SOLARBEAM, AI_CV_SunnyDay_MovesPlus - if_has_move_with_effect AI_USER_PARTNER, EFFECT_SYNTHESIS, AI_CV_SunnyDay_MovesPlus - if_has_move_with_type AI_USER, TYPE_FIRE, AI_CV_SunnyDay_MovesPlus - goto AI_CV_SunnyDay_Abilities -AI_CV_SunnyDay_MovesPlus: - score +1 -AI_CV_SunnyDay_Abilities: - if_user_faster AI_CV_SunnyDay_Abilities2 - if_ability AI_USER, ABILITY_CHLOROPHYLL, AI_CV_SunnyDay_AbilitiesPlus - get_ability AI_USER_PARTNER - if_not_equal ABILITY_CHLOROPHYLL, AI_CV_SunnyDay_Abilities2 -AI_CV_SunnyDay_AbilitiesPlus: - score +1 -AI_CV_SunnyDay_Abilities2: - if_ability AI_USER, ABILITY_LEAF_GUARD, AI_CV_SunnyDay_Abilities2Plus - get_ability AI_USER_PARTNER - if_not_equal ABILITY_LEAF_GUARD, AI_CV_SunnyDay_Opponent -AI_CV_SunnyDay_Abilities2Plus: - score + 1 -@ If target is fire type, giving him a sunny day boost may not be a good idea -AI_CV_SunnyDay_Opponent: - if_ability AI_USER, ABILITY_FLASH_FIRE, AI_CV_SunnyDay_Opponent2 - if_has_move_with_type AI_TARGET, TYPE_FIRE, AI_CV_SunnyDay_OpponentMinus - if_no_type AI_TARGET, TYPE_FIRE, AI_CV_SunnyDay_Opponent2 -AI_CV_SunnyDay_OpponentMinus: - score -1 -AI_CV_SunnyDay_Opponent2: - if_has_move_with_type AI_TARGET, TYPE_WATER, AI_CV_SunnyDay_Opponent2Plus - if_no_type AI_TARGET, TYPE_WATER, AI_CV_SunnyDay_End -AI_CV_SunnyDay_Opponent2Plus: - 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: - score +1 - end - -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 - get_last_used_bank_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_bank_move AI_TARGET - get_move_split_from_result - if_not_equal SPLIT_SPECIAL, 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: - if_has_no_special_move AI_TARGET, AI_CV_MirrorCoat_ScoreDown1 - if_random_less_than 50, AI_CV_MirrorCoat_End - -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_Geomancy: - get_hold_effect AI_USER - if_equal HOLD_EFFECT_POWER_HERB, AI_CV_ChargeUpMove_ScoreUp2 - end - -AI_CV_ChargeUpMove: - get_hold_effect AI_USER - if_equal HOLD_EFFECT_POWER_HERB, AI_CV_ChargeUpMove_ScoreUp2 - 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_ChargeUpMove_ScoreUp2: - score +2 - goto AI_CV_ChargeUpMove_End - -AI_CV_SemiInvulnerable: - get_hold_effect AI_USER - if_equal HOLD_EFFECT_POWER_HERB, AI_CV_ChargeUpMove_ScoreUp2 - if_doesnt_have_move_with_effect AI_TARGET, EFFECT_PROTECT, AI_CV_SemiInvulnerable2 - score -1 - goto AI_CV_SemiInvulnerable_End - -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_CheckIceType - if_equal AI_WEATHER_SANDSTORM, AI_CV_SemiInvulnerable_CheckSandstormTypes - 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 - get_ability AI_USER - if_in_bytes AI_SandstormResistantAbilities, 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 - get_ability AI_USER - if_in_bytes AI_HailResistantAbilities, AI_CV_SemiInvulnerable_TryEncourage - -AI_CV_SemiInvulnerable5: - if_target_faster AI_CV_SemiInvulnerable_End - get_last_used_bank_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_SandstormResistantAbilities: - .byte ABILITY_SAND_VEIL - .byte ABILITY_SAND_FORCE - .byte ABILITY_SAND_RUSH - .byte ABILITY_OVERCOAT - .byte ABILITY_MAGIC_GUARD - .byte -1 - -AI_HailResistantAbilities: - .byte ABILITY_ICE_BODY - .byte ABILITY_SNOW_CLOAK - .byte ABILITY_OVERCOAT - .byte ABILITY_MAGIC_GUARD - .byte -1 - -AI_CV_FakeOut: - if_ability AI_TARGET, ABILITY_INNER_FOCUS, AI_CV_FakeOut_End - if_double_battle AI_CV_FakeOut_Double - score +5 - end -AI_CV_FakeOut_Double: - score +2 -AI_CV_FakeOut_End: - 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_Rock -AI_CV_Hail2: - score +1 - goto AI_CV_Hail_Rock -AI_CV_Hail_ScoreDown1: - score -1 -AI_CV_Hail_Rock: - get_hold_effect AI_USER - if_not_equal HOLD_EFFECT_ICY_ROCK, AI_CV_Hail_Ability - score +2 -AI_CV_Hail_Ability: - get_ability AI_USER - if_equal ABILITY_ICE_BODY, AI_CV_Hail_AbilityPlus - if_equal ABILITY_SNOW_CLOAK, AI_CV_Hail_AbilityPlus - if_equal ABILITY_SLUSH_RUSH, AI_CV_Hail_AbilityPlus - if_not_equal ABILITY_FORECAST, AI_CV_Hail_Move -AI_CV_Hail_AbilityPlus: - score +1 -AI_CV_Hail_Move: - if_has_move AI_USER, MOVE_BLIZZARD, AI_CV_Hail_MovePlus - if_has_move AI_USER_PARTNER, MOVE_BLIZZARD, AI_CV_Hail_MovePlus - goto AI_CV_Hail_End -AI_CV_Hail_MovePlus: - score +1 -AI_CV_Hail_End: - end - -AI_CV_Sandstorm: - if_hp_less_than AI_USER, 40, AI_CV_Sandstorm_ScoreDown1 - get_weather - if_equal AI_WEATHER_SUN, AI_CV_Sandstorm2 - if_equal AI_WEATHER_RAIN, AI_CV_Sandstorm2 - if_equal AI_WEATHER_HAIL, AI_CV_Sandstorm2 - goto AI_CV_Sandstorm_End -AI_CV_Sandstorm2: - score +1 - goto AI_CV_Sandstorm_End -AI_CV_Sandstorm_ScoreDown1: - score -1 -AI_CV_Sandstorm_Rock: - get_hold_effect AI_USER - if_not_equal HOLD_EFFECT_SMOOTH_ROCK, AI_CV_Sandstorm_Ability - score +2 -AI_CV_Sandstorm_Ability: - get_ability AI_USER - if_equal ABILITY_SAND_VEIL, AI_CV_Sandstorm_AbilityPlus - if_equal ABILITY_SAND_RUSH, AI_CV_Sandstorm_AbilityPlus - if_not_equal ABILITY_SAND_VEIL, AI_CV_Sandstorm_End -AI_CV_Sandstorm_AbilityPlus: - score +1, -AI_CV_Sandstorm_End: - end - -AI_CV_Facade: - if_not_status AI_USER, 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 - if_status2 AI_USER, STATUS2_SUBSTITUTE, Score_Plus5 - -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_EffectsToEncourage2, 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_EffectsToEncourage2, 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_EffectsToEncourage2: - .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: - .byte ABILITY_SPEED_BOOST - .byte ABILITY_BATTLE_ARMOR - .byte ABILITY_SAND_VEIL - .byte ABILITY_STATIC - .byte ABILITY_FLASH_FIRE - .byte ABILITY_WONDER_GUARD - .byte ABILITY_EFFECT_SPORE - .byte ABILITY_SWIFT_SWIM - .byte ABILITY_HUGE_POWER - .byte ABILITY_RAIN_DISH - .byte ABILITY_CUTE_CHARM - .byte ABILITY_SHED_SKIN - .byte ABILITY_MARVEL_SCALE - .byte ABILITY_PURE_POWER - .byte ABILITY_CHLOROPHYLL - .byte ABILITY_SHIELD_DUST - .byte -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, DEFAULT_STAT_STAGE, 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 - -AI_CV_MagicCoat3: - if_random_less_than 50, AI_CV_MagicCoat_End - -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: - .byte ITEM_CHESTO_BERRY - .byte ITEM_LUM_BERRY - .byte ITEM_STARF_BERRY - .byte -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_SetupFirstTurn: - end - -AI_PreferStrongestMove: - end - -AI_Risky: - end - -AI_PreferBatonPass: - end - -AI_ConsiderAllyChosenMove: - get_ally_chosen_move - if_equal 0, AI_ConsiderAllyChosenMoveRet - get_move_effect_from_result - if_equal EFFECT_HELPING_HAND, AI_PartnerChoseHelpingHand - if_equal EFFECT_PERISH_SONG, AI_PartnerChosePerishSong - if_equal EFFECT_ALWAYS_CRIT, AI_PartnerChoseAlwaysCrit -AI_ConsiderAllyChosenMoveRet: - end - -@ Ally decided to use Frost Breath on us. we must have Anger Point as our ability -AI_PartnerChoseAlwaysCrit: - if_no_ability AI_USER, ABILITY_ANGER_POINT, AI_PartnerChoseAlwaysCritEnd - @frost breath user should be faster - compare_speeds AI_USER, AI_USER_PARTNER - if_not_equal 1, AI_PartnerChoseAlwaysCritEnd - get_considered_move_effect - if_in_hwords sEffectsAtkRaise, Score_Minus3 - @encourage moves hitting multiple opponents - get_considered_move_power - if_equal 0, AI_PartnerChoseAlwaysCritEnd - get_considered_move_target - if_equal MOVE_TARGET_BOTH, Score_Plus3 - if_equal MOVE_TARGET_FOES_AND_ALLY, Score_Plus3 -AI_PartnerChoseAlwaysCritEnd: - end - -.align 1 -sEffectsAtkRaise: - .2byte EFFECT_ATTACK_ACCURACY_UP - .2byte EFFECT_ATTACK_UP - .2byte EFFECT_ATTACK_UP_2 - .2byte EFFECT_DRAGON_DANCE - .2byte EFFECT_COIL - .2byte EFFECT_BELLY_DRUM - .2byte EFFECT_BULK_UP - .2byte -1 - -AI_PartnerChoseHelpingHand: - @ Do not use a status move if you know your move's power will be boosted - get_considered_move_power - if_equal 0, Score_Minus5 - end - -AI_PartnerChosePerishSong: - if_status2 AI_TARGET, STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED, AI_Ret - get_considered_move_effect - if_equal EFFECT_MEAN_LOOK, Score_Plus1 - if_equal EFFECT_TRAP, Score_Plus1 - end - -AI_ConsiderAllyKnownMoves: - @ If ally already chose a move, there is nothing to do here. - get_ally_chosen_move - if_not_equal 0, AI_Ret - if_move MOVE_HELPING_HAND, AI_HelpingHandInDoubles - if_move MOVE_PERISH_SONG, AI_PerishSongInDoubles - end - -AI_HelpingHandInDoubles: - if_has_no_attacking_moves AI_USER_PARTNER, Score_Minus5 - end - -AI_PerishSongInDoubles: - if_has_move_with_effect AI_USER_PARTNER, EFFECT_MEAN_LOOK, Score_Plus1 - if_has_move_with_effect AI_USER_PARTNER, EFFECT_TRAP, Score_Plus1 - end - -AI_DoubleBattle: - call AI_ConsiderAllyChosenMove - call AI_ConsiderAllyKnownMoves - if_target_is_ally AI_TryOnAlly - if_move MOVE_SKILL_SWAP, AI_DoubleBattleSkillSwap - get_curr_move_type - if_move MOVE_EARTHQUAKE, AI_DoubleBattleAllHittingGroundMove - if_move MOVE_MAGNITUDE, AI_DoubleBattleAllHittingGroundMove - if_equal TYPE_ELECTRIC, AI_DoubleBattleElectricMove - if_equal TYPE_FIRE, AI_DoubleBattleFireMove - get_ability AI_USER - if_not_equal ABILITY_GUTS, AI_DoubleBattleCheckUserStatus - if_has_move AI_USER_PARTNER, MOVE_HELPING_HAND, AI_DoubleBattlePartnerHasHelpingHand - end - -AI_DoubleBattlePartnerHasHelpingHand: - get_how_powerful_move_is - if_not_equal MOVE_POWER_DISCOURAGED, Score_Plus1 - end - -AI_DoubleBattleCheckUserStatus: - if_status AI_USER, STATUS1_ANY, AI_DoubleBattleCheckUserStatus2 - end - -AI_DoubleBattleCheckUserStatus2: - get_how_powerful_move_is - if_equal MOVE_POWER_DISCOURAGED, Score_Minus5 - score +1 - if_equal MOVE_POWER_BEST, Score_Plus2 - end - -AI_DoubleBattleAllHittingGroundMove: - if_ability AI_USER_PARTNER, ABILITY_LEVITATE, Score_Plus2 - if_type AI_USER_PARTNER, TYPE_FLYING, Score_Plus2 - if_type AI_USER_PARTNER, TYPE_FIRE, Score_Minus10 - if_type AI_USER_PARTNER, TYPE_ELECTRIC, Score_Minus10 - if_type AI_USER_PARTNER, TYPE_POISON, Score_Minus10 - if_type AI_USER_PARTNER, TYPE_ROCK, Score_Minus10 - goto Score_Minus3 - -AI_DoubleBattleSkillSwap: - get_ability AI_USER - if_equal ABILITY_TRUANT, Score_Plus5 - get_ability AI_TARGET - if_equal ABILITY_SHADOW_TAG, Score_Plus2 - if_equal ABILITY_PURE_POWER, Score_Plus2 - end - -AI_DoubleBattleElectricMove: - if_no_ability AI_TARGET_PARTNER, ABILITY_LIGHTNING_ROD, AI_DoubleBattleElectricMoveEnd - score -2 - if_no_type AI_TARGET_PARTNER, TYPE_GROUND, AI_DoubleBattleElectricMoveEnd - score -8 - -AI_DoubleBattleElectricMoveEnd: - end - -AI_DoubleBattleFireMove: - if_flash_fired AI_USER, AI_DoubleBattleFireMove2 - end - -AI_DoubleBattleFireMove2: - goto Score_Plus1 - -AI_TryOnAlly: - get_how_powerful_move_is - if_equal MOVE_POWER_DISCOURAGED, AI_TryStatusMoveOnAlly - get_curr_move_type - if_equal TYPE_FIRE, AI_TryFireMoveOnAlly - if_effect EFFECT_ALWAYS_CRIT, AI_TryCritAngerPointAlly -AI_DiscourageOnAlly: - goto Score_Minus30 - -AI_TryFireMoveOnAlly: - if_ability AI_USER_PARTNER, ABILITY_FLASH_FIRE, AI_TryFireMoveOnAlly_FlashFire - goto AI_DiscourageOnAlly -AI_TryFireMoveOnAlly_FlashFire: - if_flash_fired AI_USER_PARTNER, AI_DiscourageOnAlly - goto Score_Plus3 - -AI_TryCritAngerPointAlly: - get_ability AI_USER_PARTNER - if_not_equal ABILITY_ANGER_POINT, AI_DiscourageOnAlly - if_stat_level_more_than AI_USER_PARTNER, STAT_ATK, 8, AI_DiscourageOnAlly - if_status2 AI_USER_PARTNER, STATUS2_SUBSTITUTE, AI_DiscourageOnAlly - if_has_no_move_with_split AI_USER_PARTNER, SPLIT_PHYSICAL, AI_DiscourageOnAlly - get_curr_dmg_hp_percent - if_more_than 34,AI_DiscourageOnAlly - if_hp_less_than AI_USER_PARTNER, 60, AI_DiscourageOnAlly - goto Score_Plus3 - -AI_TryStatusMoveOnAlly: - if_move MOVE_SKILL_SWAP, AI_TrySkillSwapOnAlly - if_move MOVE_WILL_O_WISP, AI_TryStatusOnAlly - if_move MOVE_TOXIC, AI_TryStatusOnAlly - if_move MOVE_HELPING_HAND, AI_TryHelpingHandOnAlly - if_move MOVE_SWAGGER, AI_TrySwaggerOnAlly - goto Score_Minus30 - -AI_TrySkillSwapOnAlly: - get_ability AI_TARGET - if_equal ABILITY_TRUANT, Score_Plus10 - get_ability AI_USER - if_not_equal ABILITY_LEVITATE, AI_TrySkillSwapOnAlly2 - get_ability AI_TARGET - if_equal ABILITY_LEVITATE, Score_Minus30 - get_target_type1 - if_not_equal TYPE_ELECTRIC, AI_TrySkillSwapOnAlly2 - score +1 - get_target_type2 - if_not_equal TYPE_ELECTRIC, AI_TrySkillSwapOnAlly2 - score +1 - end - -AI_TrySkillSwapOnAlly2: - if_not_equal ABILITY_COMPOUND_EYES, Score_Minus30 - if_has_move AI_USER_PARTNER, MOVE_FIRE_BLAST, AI_TrySkillSwapOnAllyPlus3 - if_has_move AI_USER_PARTNER, MOVE_THUNDER, AI_TrySkillSwapOnAllyPlus3 - if_has_move AI_USER_PARTNER, MOVE_CROSS_CHOP, AI_TrySkillSwapOnAllyPlus3 - if_has_move AI_USER_PARTNER, MOVE_HYDRO_PUMP, AI_TrySkillSwapOnAllyPlus3 - if_has_move AI_USER_PARTNER, MOVE_DYNAMIC_PUNCH, AI_TrySkillSwapOnAllyPlus3 - if_has_move AI_USER_PARTNER, MOVE_BLIZZARD, AI_TrySkillSwapOnAllyPlus3 - if_has_move AI_USER_PARTNER, MOVE_MEGAHORN, AI_TrySkillSwapOnAllyPlus3 - goto Score_Minus30 - -AI_TrySkillSwapOnAllyPlus3: - goto Score_Plus3 - -AI_TryStatusOnAlly: - get_ability AI_TARGET - if_not_equal ABILITY_GUTS, Score_Minus30 - if_status AI_TARGET, STATUS1_ANY, Score_Minus30 - if_hp_less_than AI_USER, 91, Score_Minus30 - goto Score_Plus5 - -AI_TryHelpingHandOnAlly: - if_random_less_than 64, Score_Minus1 - goto Score_Plus2 - -AI_TrySwaggerOnAlly: - if_has_no_physical_move AI_USER_PARTNER, Score_Minus30 - if_holds_item AI_TARGET, ITEM_PERSIM_BERRY, AI_TrySwaggerOnAlly2 - if_ability AI_USER_PARTNER, ABILITY_OWN_TEMPO, AI_TrySwaggerOnAlly2 - goto Score_Minus30 - -AI_TrySwaggerOnAlly2: - if_stat_level_more_than AI_TARGET, STAT_ATK, 7, AI_TrySwaggerOnAlly_End - score +3 - -AI_TrySwaggerOnAlly_End: - end - -AI_HPAware: - if_target_is_ally AI_TryOnAlly - 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_hwords 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 - -.align 1 -AI_HPAware_DiscouragedEffectsWhenHighHP: @ 82DE21F - .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_SHORE_UP - .2byte EFFECT_SOFTBOILED - .2byte EFFECT_ROOST - .2byte EFFECT_MEMENTO - .2byte EFFECT_GRUDGE - .2byte EFFECT_OVERHEAT - .2byte -1 - -AI_HPAware_DiscouragedEffectsWhenMediumHP: @ 82DE22D - .byte EFFECT_EXPLOSION - .byte EFFECT_ATTACK_UP - .byte EFFECT_DEFENSE_UP - .byte EFFECT_SPEED_UP - .byte EFFECT_SPECIAL_ATTACK_UP - .byte EFFECT_SPECIAL_DEFENSE_UP - .byte EFFECT_ACCURACY_UP - .byte EFFECT_EVASION_UP - .byte EFFECT_ATTACK_DOWN - .byte EFFECT_DEFENSE_DOWN - .byte EFFECT_SPEED_DOWN - .byte EFFECT_SPECIAL_ATTACK_DOWN - .byte EFFECT_SPECIAL_DEFENSE_DOWN - .byte EFFECT_ACCURACY_DOWN - .byte EFFECT_EVASION_DOWN - .byte EFFECT_BIDE - .byte EFFECT_CONVERSION - .byte EFFECT_LIGHT_SCREEN - .byte EFFECT_MIST - .byte EFFECT_FOCUS_ENERGY - .byte EFFECT_ATTACK_UP_2 - .byte EFFECT_DEFENSE_UP_2 - .byte EFFECT_SPEED_UP_2 - .byte EFFECT_SPECIAL_ATTACK_UP_2 - .byte EFFECT_SPECIAL_DEFENSE_UP_2 - .byte EFFECT_ACCURACY_UP_2 - .byte EFFECT_EVASION_UP_2 - .byte EFFECT_ATTACK_DOWN_2 - .byte EFFECT_DEFENSE_DOWN_2 - .byte EFFECT_SPEED_DOWN_2 - .byte EFFECT_SPECIAL_ATTACK_DOWN_2 - .byte EFFECT_SPECIAL_DEFENSE_DOWN_2 - .byte EFFECT_ACCURACY_DOWN_2 - .byte EFFECT_EVASION_DOWN_2 - .byte EFFECT_CONVERSION_2 - .byte EFFECT_SAFEGUARD - .byte EFFECT_BELLY_DRUM - .byte EFFECT_TICKLE - .byte EFFECT_COSMIC_POWER - .byte EFFECT_BULK_UP - .byte EFFECT_CALM_MIND - .byte EFFECT_DRAGON_DANCE - .byte -1 - -AI_HPAware_DiscouragedEffectsWhenLowHP: @ 82DE258 - .byte EFFECT_ATTACK_UP - .byte EFFECT_DEFENSE_UP - .byte EFFECT_SPEED_UP - .byte EFFECT_SPECIAL_ATTACK_UP - .byte EFFECT_SPECIAL_DEFENSE_UP - .byte EFFECT_ACCURACY_UP - .byte EFFECT_EVASION_UP - .byte EFFECT_ATTACK_DOWN - .byte EFFECT_DEFENSE_DOWN - .byte EFFECT_SPEED_DOWN - .byte EFFECT_SPECIAL_ATTACK_DOWN - .byte EFFECT_SPECIAL_DEFENSE_DOWN - .byte EFFECT_ACCURACY_DOWN - .byte EFFECT_EVASION_DOWN - .byte EFFECT_BIDE - .byte EFFECT_CONVERSION - .byte EFFECT_LIGHT_SCREEN - .byte EFFECT_MIST - .byte EFFECT_FOCUS_ENERGY - .byte EFFECT_ATTACK_UP_2 - .byte EFFECT_DEFENSE_UP_2 - .byte EFFECT_SPEED_UP_2 - .byte EFFECT_SPECIAL_ATTACK_UP_2 - .byte EFFECT_SPECIAL_DEFENSE_UP_2 - .byte EFFECT_ACCURACY_UP_2 - .byte EFFECT_EVASION_UP_2 - .byte EFFECT_ATTACK_DOWN_2 - .byte EFFECT_DEFENSE_DOWN_2 - .byte EFFECT_SPEED_DOWN_2 - .byte EFFECT_SPECIAL_ATTACK_DOWN_2 - .byte EFFECT_SPECIAL_DEFENSE_DOWN_2 - .byte EFFECT_ACCURACY_DOWN_2 - .byte EFFECT_EVASION_DOWN_2 - .byte EFFECT_RAGE - .byte EFFECT_CONVERSION_2 - .byte EFFECT_LOCK_ON - .byte EFFECT_SAFEGUARD - .byte EFFECT_BELLY_DRUM - .byte EFFECT_PSYCH_UP - .byte EFFECT_MIRROR_COAT - .byte EFFECT_SOLARBEAM - .byte EFFECT_ERUPTION - .byte EFFECT_TICKLE - .byte EFFECT_COSMIC_POWER - .byte EFFECT_BULK_UP - .byte EFFECT_CALM_MIND - .byte EFFECT_DRAGON_DANCE - .byte -1 - -AI_HPAware_DiscouragedEffectsWhenTargetHighHP: @ 82DE288 - .byte -1 - -AI_HPAware_DiscouragedEffectsWhenTargetMediumHP: @ 82DE289 - .byte EFFECT_ATTACK_UP - .byte EFFECT_DEFENSE_UP - .byte EFFECT_SPEED_UP - .byte EFFECT_SPECIAL_ATTACK_UP - .byte EFFECT_SPECIAL_DEFENSE_UP - .byte EFFECT_ACCURACY_UP - .byte EFFECT_EVASION_UP - .byte EFFECT_ATTACK_DOWN - .byte EFFECT_DEFENSE_DOWN - .byte EFFECT_SPEED_DOWN - .byte EFFECT_SPECIAL_ATTACK_DOWN - .byte EFFECT_SPECIAL_DEFENSE_DOWN - .byte EFFECT_ACCURACY_DOWN - .byte EFFECT_EVASION_DOWN - .byte EFFECT_MIST - .byte EFFECT_FOCUS_ENERGY - .byte EFFECT_ATTACK_UP_2 - .byte EFFECT_DEFENSE_UP_2 - .byte EFFECT_SPEED_UP_2 - .byte EFFECT_SPECIAL_ATTACK_UP_2 - .byte EFFECT_SPECIAL_DEFENSE_UP_2 - .byte EFFECT_ACCURACY_UP_2 - .byte EFFECT_EVASION_UP_2 - .byte EFFECT_ATTACK_DOWN_2 - .byte EFFECT_DEFENSE_DOWN_2 - .byte EFFECT_SPEED_DOWN_2 - .byte EFFECT_SPECIAL_ATTACK_DOWN_2 - .byte EFFECT_SPECIAL_DEFENSE_DOWN_2 - .byte EFFECT_ACCURACY_DOWN_2 - .byte EFFECT_EVASION_DOWN_2 - .byte EFFECT_POISON - .byte EFFECT_PAIN_SPLIT - .byte EFFECT_PERISH_SONG - .byte EFFECT_SAFEGUARD - .byte EFFECT_TICKLE - .byte EFFECT_COSMIC_POWER - .byte EFFECT_BULK_UP - .byte EFFECT_CALM_MIND - .byte EFFECT_DRAGON_DANCE - .byte -1 - -AI_HPAware_DiscouragedEffectsWhenTargetLowHP: @ 82DE2B1 - .byte EFFECT_SLEEP - .byte EFFECT_EXPLOSION - .byte EFFECT_ATTACK_UP - .byte EFFECT_DEFENSE_UP - .byte EFFECT_SPEED_UP - .byte EFFECT_SPECIAL_ATTACK_UP - .byte EFFECT_SPECIAL_DEFENSE_UP - .byte EFFECT_ACCURACY_UP - .byte EFFECT_EVASION_UP - .byte EFFECT_ATTACK_DOWN - .byte EFFECT_DEFENSE_DOWN - .byte EFFECT_SPEED_DOWN - .byte EFFECT_SPECIAL_ATTACK_DOWN - .byte EFFECT_SPECIAL_DEFENSE_DOWN - .byte EFFECT_ACCURACY_DOWN - .byte EFFECT_EVASION_DOWN - .byte EFFECT_BIDE - .byte EFFECT_CONVERSION - .byte EFFECT_TOXIC - .byte EFFECT_LIGHT_SCREEN - .byte EFFECT_OHKO - .byte EFFECT_SUPER_FANG - .byte EFFECT_MIST - .byte EFFECT_FOCUS_ENERGY - .byte EFFECT_CONFUSE - .byte EFFECT_ATTACK_UP_2 - .byte EFFECT_DEFENSE_UP_2 - .byte EFFECT_SPEED_UP_2 - .byte EFFECT_SPECIAL_ATTACK_UP_2 - .byte EFFECT_SPECIAL_DEFENSE_UP_2 - .byte EFFECT_ACCURACY_UP_2 - .byte EFFECT_EVASION_UP_2 - .byte EFFECT_ATTACK_DOWN_2 - .byte EFFECT_DEFENSE_DOWN_2 - .byte EFFECT_SPEED_DOWN_2 - .byte EFFECT_SPECIAL_ATTACK_DOWN_2 - .byte EFFECT_SPECIAL_DEFENSE_DOWN_2 - .byte EFFECT_ACCURACY_DOWN_2 - .byte EFFECT_EVASION_DOWN_2 - .byte EFFECT_POISON - .byte EFFECT_PARALYZE - .byte EFFECT_PAIN_SPLIT - .byte EFFECT_CONVERSION_2 - .byte EFFECT_LOCK_ON - .byte EFFECT_SPITE - .byte EFFECT_PERISH_SONG - .byte EFFECT_SWAGGER - .byte EFFECT_FURY_CUTTER - .byte EFFECT_ATTRACT - .byte EFFECT_SAFEGUARD - .byte EFFECT_PSYCH_UP - .byte EFFECT_MIRROR_COAT - .byte EFFECT_WILL_O_WISP - .byte EFFECT_TICKLE - .byte EFFECT_COSMIC_POWER - .byte EFFECT_BULK_UP - .byte EFFECT_CALM_MIND - .byte EFFECT_DRAGON_DANCE - .byte -1 - - - -AI_Ret: - end diff --git a/include/battle.h b/include/battle.h index 12fe42f8f1..ba033f5fee 100644 --- a/include/battle.h +++ b/include/battle.h @@ -316,7 +316,6 @@ struct BattleResources struct StatsArray* beforeLvlUp; struct AI_ThinkingStruct *ai; struct BattleHistory *battleHistory; - struct BattleScriptsStack *AI_ScriptsStack; u8 bufferA[MAX_BATTLERS_COUNT][0x200]; u8 bufferB[MAX_BATTLERS_COUNT][0x200]; }; diff --git a/include/battle_ai_script_commands.h b/include/battle_ai_main.h similarity index 53% rename from include/battle_ai_script_commands.h rename to include/battle_ai_main.h index 75d96ff52d..52da9359a0 100644 --- a/include/battle_ai_script_commands.h +++ b/include/battle_ai_main.h @@ -1,5 +1,5 @@ -#ifndef GUARD_BATTLE_AI_SCRIPT_COMMANDS_H -#define GUARD_BATTLE_AI_SCRIPT_COMMANDS_H +#ifndef GUARD_BATTLE_AI_MAIN_H +#define GUARD_BATTLE_AI_MAIN_H // return values for BattleAI_ChooseMoveOrAction // 0 - 3 are move idx @@ -11,10 +11,7 @@ void BattleAI_SetupItems(void); void BattleAI_SetupFlags(void); void BattleAI_SetupAIData(u8 defaultScoreMoves); u8 BattleAI_ChooseMoveOrAction(void); -bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler); -bool32 IsBattlerAIControlled(u32 battlerId); -void ClearBattlerMoveHistory(u8 battlerId); extern u8 sBattler_AI; -#endif // GUARD_BATTLE_AI_SCRIPT_COMMANDS_H +#endif // GUARD_BATTLE_AI_MAIN_H diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 7fd991bf2c..428e47e23c 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -20,6 +20,8 @@ void SaveBattlerData(u8 battlerId); void SetBattlerData(u8 battlerId); void RestoreBattlerData(u8 battlerId); +u32 GetTotalBaseStat(u32 species); +bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler); bool32 AtMaxHp(u8 battler); u32 GetHealthPercentage(u8 battler); bool32 IsBattlerTrapped(u8 battler, bool8 switching); @@ -105,12 +107,17 @@ bool32 HasHealingEffect(u32 battler); bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move); bool32 IsThawingMove(u16 move); bool32 HasThawingMove(u8 battlerId); +bool32 IsStatRaisingEffect(u16 effect); +bool32 IsStatLoweringEffect(u16 effect); +bool32 IsStatRaisingEffect(u16 effect); +bool32 IsAttackBoostMoveEffect(u16 effect); // status checks bool32 CanBeBurned(u8 battler, u16 ability); bool32 CanBePoisoned(u8 battler, u16 ability); -bool32 IsBattlerIncapacitated(u8 battler, u16 ability); +bool32 CanBeConfused(u8 battler, u16 ability); bool32 CanSleep(u8 battler, u16 ability); +bool32 IsBattlerIncapacitated(u8 battler, u16 ability); bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); bool32 ShouldPoisonSelf(u8 battler, u16 ability); bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 3dac82bc43..43a21fa0f2 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -43,12 +43,13 @@ #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) +#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) -// Flags that don't run specific checks themselves, but are used in other score functions -#define AI_FLAG_NEGATE_AWARE (1 << 9) // AI is aware of negating effects like wonder room, mold breaker, etc (eg. smart trainers). TODO unfinished -#define AI_FLAG_HELP_PARTNER (1 << 10) // AI can try to help partner. If not set, will tend not to target partner -#define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc +// New, Trainer Handicap Flags +#define AI_FLAG_NEGATE_UNAWARE (1 << 9) // AI is NOT aware of negating effects like wonder room, mold breaker, etc +#define AI_FLAG_WILL_SUICIDE (1 << 10) // AI will use explosion / self destruct / final gambit / etc +// New, Trainer Strategy Flags +#define AI_FLAG_HELP_PARTNER (1 << 11) // AI can try to help partner. If not set, will tend not to target partner #define AI_FLAG_PREFER_STATUS_MOVES (1 << 12) // 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 << 13) // AI stalls battle and prefers secondary damage/trapping/etc. TODO not finished #define AI_FLAG_SCREENER (1 << 14) // AI prefers screening effects like reflect, mist, etc. TODO unfinished diff --git a/ld_script.txt b/ld_script.txt index c6276922a9..dd5907d59f 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -213,7 +213,7 @@ SECTIONS { src/decoration.o(.text); src/slot_machine.o(.text); src/contest_painting.o(.text); - src/battle_ai_script_commands.o(.text); + src/battle_ai_main.o(.text); src/battle_ai_util.o(.text); src/trader.o(.text); src/starter_choose.o(.text); @@ -346,7 +346,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/contest_ai_scripts.o(script_data); data/mystery_event_script_cmd_table.o(script_data); } =0 @@ -589,7 +588,7 @@ SECTIONS { src/decoration.o(.rodata); src/slot_machine.o(.rodata); src/contest_painting.o(.rodata); - src/battle_ai_script_commands.o(.rodata); + src/battle_ai_main.o(.rodata); src/battle_ai_util.o(.rodata); src/trader.o(.rodata); src/starter_choose.o(.rodata); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_main.c similarity index 77% rename from src/battle_ai_script_commands.c rename to src/battle_ai_main.c index 55597e98a6..ec23986298 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_main.c @@ -3,7 +3,7 @@ #include "battle.h" #include "battle_anim.h" #include "battle_ai_util.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_factory.h" #include "battle_setup.h" #include "data.h" @@ -37,150 +37,15 @@ enum AIState_DoNotProcess }; -/* -gAIScriptPtr is a pointer to the next battle AI cmd command to read. -when a command finishes processing, gAIScriptPtr 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 u8 ChooseMoveOrAction_Singles(void); static u8 ChooseMoveOrAction_Doubles(void); static void BattleAI_DoAIProcessing(void); -static void AIStackPushVar(const u8 *); -static bool8 AIStackPop(void); - -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_u32(void); -static void Cmd_if_not_equal_u32(void); -static void Cmd_if_user_goes(void); -static void Cmd_if_cant_use_belch(void); -static void Cmd_nullsub_2A(void); -static void Cmd_nullsub_2B(void); -static void Cmd_count_usable_party_mons(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_if_move_flag(void); -static void Cmd_if_field_status(void); -static void Cmd_get_move_accuracy(void); -static void Cmd_call_if_eq(void); -static void Cmd_call_if_move_flag(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_cond(void); -static void Cmd_if_target_taunted(void); -static void Cmd_if_target_not_taunted(void); -static void Cmd_check_ability(void); -static void Cmd_is_of_type(void); -static void Cmd_if_target_is_ally(void); -static void Cmd_if_flash_fired(void); -static void Cmd_if_holds_item(void); -static void Cmd_get_ally_chosen_move(void); -static void Cmd_if_has_no_attacking_moves(void); -static void Cmd_get_hazards_count(void); -static void Cmd_if_doesnt_hold_berry(void); -static void Cmd_if_share_type(void); -static void Cmd_if_cant_use_last_resort(void); -static void Cmd_if_has_move_with_split(void); -static void Cmd_if_has_no_move_with_split(void); -static void Cmd_if_physical_moves_unusable(void); -static void Cmd_if_ai_can_go_down(void); -static void Cmd_if_has_move_with_type(void); -static void Cmd_if_no_move_used(void); -static void Cmd_if_has_move_with_flag(void); -static void Cmd_if_battler_absent(void); -static void Cmd_is_grounded(void); -static void Cmd_get_best_dmg_hp_percent(void); -static void Cmd_get_curr_dmg_hp_percent(void); -static void Cmd_get_move_split_from_result(void); -static void Cmd_get_considered_move_split(void); -static void Cmd_get_considered_move_target(void); -static void Cmd_compare_speeds(void); -static void Cmd_is_wakeup_turn(void); -static void Cmd_if_has_move_with_accuracy_lt(void); // ewram -EWRAM_DATA const u8 *gAIScriptPtr = NULL; +EWRAM_DATA const u8 *gAIScriptPtr = NULL; // Still used in contests EWRAM_DATA u8 sBattler_AI = 0; // const rom data -typedef void (*BattleAICmdFunc)(void); - static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); @@ -188,7 +53,6 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); @@ -203,11 +67,11 @@ static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = [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 + [7] = NULL, // AI_FLAG_DOUBLE_BATTLE. split between AI_CheckBadMove & AI_CheckGoodMove [8] = AI_HPAware, // AI_FLAG_HP_AWARE - [9] = NULL, // AI_FLAG_NEGATE_AWARE - [10] = NULL, // AI_FLAG_HELP_PARTNER - [11] = NULL, // AI_FLAG_WILL_SUICIDE + [9] = NULL, // AI_FLAG_NEGATE_UNAWARE + [10] = NULL, // AI_FLAG_WILL_SUICIDE + [11] = NULL, // AI_FLAG_HELP_PARTNER [12] = NULL, // Unused [13] = NULL, // Unused [14] = NULL, // Unused @@ -230,133 +94,7 @@ static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = [31] = AI_FirstBattle, // AI_FLAG_FIRST_BATTLE }; -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_u32, // 0x26 - Cmd_if_not_equal_u32, // 0x27 - Cmd_if_user_goes, // 0x28 - Cmd_if_cant_use_belch, // 0x29 - Cmd_nullsub_2A, // 0x2A - Cmd_nullsub_2B, // 0x2B - Cmd_count_usable_party_mons, // 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_if_move_flag, // 0x52 - Cmd_if_field_status, // 0x53 - Cmd_get_move_accuracy, // 0x54 - Cmd_call_if_eq, // 0x55 - Cmd_call_if_move_flag, // 0x56 - Cmd_nullsub_57, // 0x57 - Cmd_call, // 0x58 - Cmd_goto, // 0x59 - Cmd_end, // 0x5A - Cmd_if_level_cond, // 0x5B - Cmd_if_target_taunted, // 0x5C - Cmd_if_target_not_taunted, // 0x5D - Cmd_if_target_is_ally, // 0x5E - Cmd_is_of_type, // 0x5F - Cmd_check_ability, // 0x60 - Cmd_if_flash_fired, // 0x61 - Cmd_if_holds_item, // 0x62 - Cmd_get_ally_chosen_move, // 0x63 - Cmd_if_has_no_attacking_moves, // 0x64 - Cmd_get_hazards_count, // 0x65 - Cmd_if_doesnt_hold_berry, // 0x66 - Cmd_if_share_type, // 0x67 - Cmd_if_cant_use_last_resort, // 0x68 - Cmd_if_has_move_with_split, // 0x69 - Cmd_if_has_no_move_with_split, // 0x6A - Cmd_if_physical_moves_unusable, // 0x6B - Cmd_if_ai_can_go_down, // 0x6C - Cmd_if_has_move_with_type, // 0x6D - Cmd_if_no_move_used, // 0x6E - Cmd_if_has_move_with_flag, // 0x6F - Cmd_if_battler_absent, // 0x70 - Cmd_is_grounded, // 0x71 - Cmd_get_best_dmg_hp_percent, // 0x72 - Cmd_get_curr_dmg_hp_percent, // 0x73 - Cmd_get_move_split_from_result, // 0x74 - Cmd_get_considered_move_split, // 0x75 - Cmd_get_considered_move_target, // 0x76 - Cmd_compare_speeds, // 0x77 - Cmd_is_wakeup_turn, // 0x78 - Cmd_if_has_move_with_accuracy_lt, // 0x79 -}; - -// code +// Functions void BattleAI_SetupItems(void) { s32 i; @@ -437,9 +175,7 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves) AI_THINKING_STRUCT->score[i] = 0; } - gBattleResources->AI_ScriptsStack->size = 0; sBattler_AI = gActiveBattler; - // Simulate dmg for all AI moves against all opposing targets for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) { @@ -477,31 +213,6 @@ u8 BattleAI_ChooseMoveOrAction(void) return ret; } -static u32 GetTotalBaseStat(u32 species) -{ - return gBaseStats[species].baseHP - + gBaseStats[species].baseAttack - + gBaseStats[species].baseDefense - + gBaseStats[species].baseSpeed - + gBaseStats[species].baseSpAttack - + gBaseStats[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 (gBattleMoves[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE) - return TRUE; - if (gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAI, opposingBattler, TRUE) == 1) - return TRUE; - } - return FALSE; -} - static void GetAiLogicData(u8 battlerAtk, u8 battlerDef) { // attacker data @@ -653,9 +364,10 @@ static u8 ChooseMoveOrAction_Doubles(void) BattleAI_SetupAIData(gBattleStruct->palaceFlags >> 4); else BattleAI_SetupAIData((1 << MAX_MON_MOVES) - 1); - + gBattlerTarget = i; - + GetAiLogicData(sBattler_AI, gBattlerTarget); + if ((i & BIT_SIDE) != (sBattler_AI & BIT_SIDE)) RecordLastUsedMoveByTarget(); @@ -765,1565 +477,36 @@ static void BattleAI_DoAIProcessing(void) break; case AIState_Processing: if (AI_THINKING_STRUCT->moveConsidered != MOVE_NONE - && AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] > 0) - { - if (AI_THINKING_STRUCT->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable) - && sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId] != NULL) - { + && AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] > 0) + { + if (AI_THINKING_STRUCT->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable) + && sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId] != NULL) + { // Call AI function - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = - sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId](gBattlerAttacker, + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = + sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId](gBattlerAttacker, gBattlerTarget, AI_THINKING_STRUCT->moveConsidered, AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex]); - } - } - else - { - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; - } + } + } + else + { + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; + } - AI_THINKING_STRUCT->movesetIndex++; - if (AI_THINKING_STRUCT->movesetIndex < MAX_MON_MOVES && !(AI_THINKING_STRUCT->aiAction & AI_ACTION_DO_NOT_ATTACK)) - AI_THINKING_STRUCT->aiState = AIState_SettingUp; - else - AI_THINKING_STRUCT->aiState++; + AI_THINKING_STRUCT->movesetIndex++; + if (AI_THINKING_STRUCT->movesetIndex < MAX_MON_MOVES && !(AI_THINKING_STRUCT->aiAction & AI_ACTION_DO_NOT_ATTACK)) + AI_THINKING_STRUCT->aiState = AIState_SettingUp; + else + AI_THINKING_STRUCT->aiState++; break; } } } -static void Cmd_if_random_less_than(void) -{ - u16 random = Random(); - - if (random % 256 < gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_if_random_greater_than(void) -{ - u16 random = Random(); - - if (random % 256 > gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_if_random_equal(void) -{ - u16 random = Random(); - - if (random % 256 == gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_if_random_not_equal(void) -{ - u16 random = Random(); - - if (random % 256 != gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_score(void) -{ - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] += gAIScriptPtr[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; - - gAIScriptPtr += 2; // AI return. -} - -static u8 BattleAI_GetWantedBattler(u8 wantedBattler) -{ - switch (wantedBattler) - { - case AI_USER: - return sBattler_AI; - case AI_TARGET: - default: - return gBattlerTarget; - case AI_USER_PARTNER: - return sBattler_AI ^ BIT_FLANK; - case AI_TARGET_PARTNER: - return gBattlerTarget ^ BIT_FLANK; - } -} - -static void Cmd_if_hp_less_than(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if ((u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP) < gAIScriptPtr[2]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_hp_more_than(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if ((u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP) > gAIScriptPtr[2]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_hp_equal(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if ((u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP) == gAIScriptPtr[2]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_hp_not_equal(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if ((u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP) != gAIScriptPtr[2]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_status(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 status = T1_READ_32(gAIScriptPtr + 2); - - if (gBattleMons[battlerId].status1 & status) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void Cmd_if_not_status(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 status = T1_READ_32(gAIScriptPtr + 2); - - if (!(gBattleMons[battlerId].status1 & status)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void Cmd_if_status2(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 status = T1_READ_32(gAIScriptPtr + 2); - - if ((gBattleMons[battlerId].status2 & status)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void Cmd_if_not_status2(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 status = T1_READ_32(gAIScriptPtr + 2); - - if (!(gBattleMons[battlerId].status2 & status)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void Cmd_if_status3(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 status = T1_READ_32(gAIScriptPtr + 2); - - if (gStatuses3[battlerId] & status) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void Cmd_if_not_status3(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 status = T1_READ_32(gAIScriptPtr + 2); - - if (!(gStatuses3[battlerId] & status)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void Cmd_if_side_affecting(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 status = T1_READ_32(gAIScriptPtr + 2); - u32 side = GET_BATTLER_SIDE(battlerId); - - if (gSideStatuses[side] & status) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void Cmd_if_not_side_affecting(void) -{ - u16 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 status = T1_READ_32(gAIScriptPtr + 2); - u32 side = GET_BATTLER_SIDE(battlerId); - - if (!(gSideStatuses[side] & status)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void Cmd_if_less_than(void) -{ - if (AI_THINKING_STRUCT->funcResult < gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_if_more_than(void) -{ - if (AI_THINKING_STRUCT->funcResult > gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_if_equal(void) -{ - if (AI_THINKING_STRUCT->funcResult == gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_if_not_equal(void) -{ - if (AI_THINKING_STRUCT->funcResult != gAIScriptPtr[1]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_if_less_than_ptr(void) -{ - const u8 *value = T1_READ_PTR(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult < *value) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void Cmd_if_more_than_ptr(void) -{ - const u8 *value = T1_READ_PTR(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult > *value) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void Cmd_if_equal_ptr(void) -{ - const u8 *value = T1_READ_PTR(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult == *value) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void Cmd_if_not_equal_ptr(void) -{ - const u8 *value = T1_READ_PTR(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult != *value) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void Cmd_if_move(void) -{ - u16 move = T1_READ_16(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->moveConsidered == move) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_not_move(void) -{ - u16 move = T1_READ_16(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->moveConsidered != move) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_in_bytes(void) -{ - const u8 *ptr = T1_READ_PTR(gAIScriptPtr + 1); - - while (*ptr != 0xFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - return; - } - ptr++; - } - gAIScriptPtr += 9; -} - -static void Cmd_if_not_in_bytes(void) -{ - const u8 *ptr = T1_READ_PTR(gAIScriptPtr + 1); - - while (*ptr != 0xFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - gAIScriptPtr += 9; - return; - } - ptr++; - } - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); -} - -static void Cmd_if_in_hwords(void) -{ - const u16 *ptr = (const u16 *)T1_READ_PTR(gAIScriptPtr + 1); - - while (*ptr != 0xFFFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - return; - } - ptr++; - } - gAIScriptPtr += 9; -} - -static void Cmd_if_not_in_hwords(void) -{ - const u16 *ptr = (const u16 *)T1_READ_PTR(gAIScriptPtr + 1); - - while (*ptr != 0xFFFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - gAIScriptPtr += 9; - return; - } - ptr++; - } - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); -} - -static void Cmd_if_user_has_attacking_move(void) -{ - s32 i; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[sBattler_AI].moves[i] != 0 - && gBattleMoves[gBattleMons[sBattler_AI].moves[i]].power != 0) - break; - } - - if (i == MAX_MON_MOVES) - gAIScriptPtr += 5; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); -} - -static void Cmd_if_user_has_no_attacking_moves(void) -{ - //HasDamagingMove -} - -static void Cmd_get_turn_count(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleResults.battleTurnCounter; - gAIScriptPtr += 1; -} - -static void Cmd_get_type(void) -{ - u8 typeVar = gAIScriptPtr[1]; - - switch (typeVar) - { - case AI_TYPE1_USER: // AI user primary type - AI_THINKING_STRUCT->funcResult = gBattleMons[sBattler_AI].type1; - break; - case AI_TYPE1_TARGET: // target primary type - AI_THINKING_STRUCT->funcResult = gBattleMons[gBattlerTarget].type1; - break; - case AI_TYPE2_USER: // AI user secondary type - AI_THINKING_STRUCT->funcResult = gBattleMons[sBattler_AI].type2; - break; - case AI_TYPE2_TARGET: // target secondary type - AI_THINKING_STRUCT->funcResult = gBattleMons[gBattlerTarget].type2; - break; - case AI_TYPE_MOVE: // type of move being pointed to - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].type; - break; - } - gAIScriptPtr += 2; -} - -static void Cmd_is_of_type(void) -{ - u8 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if (IS_BATTLER_OF_TYPE(battlerId, gAIScriptPtr[2])) - AI_THINKING_STRUCT->funcResult = TRUE; - else - AI_THINKING_STRUCT->funcResult = FALSE; - - gAIScriptPtr += 3; -} - -static void Cmd_get_considered_move_power(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power; - gAIScriptPtr += 1; -} - - - -static void Cmd_get_how_powerful_move_is(void) -{ - // GetMoveDamageResult -} - -static void Cmd_get_last_used_battler_move(void) -{ - AI_THINKING_STRUCT->funcResult = gLastMoves[BattleAI_GetWantedBattler(gAIScriptPtr[1])]; - gAIScriptPtr += 2; -} - -static void Cmd_if_equal_u32(void) -{ - if (T1_READ_32(&gAIScriptPtr[1]) == AI_THINKING_STRUCT->funcResult) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void Cmd_if_not_equal_u32(void) -{ - if (T1_READ_32(&gAIScriptPtr[1]) != AI_THINKING_STRUCT->funcResult) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void Cmd_if_user_goes(void) -{ - // IsAiFaster -} - -static void Cmd_nullsub_2A(void) -{ -} - -static void Cmd_nullsub_2B(void) -{ -} - -static void Cmd_count_usable_party_mons(void) -{ - AI_THINKING_STRUCT->funcResult = CountUsablePartyMons(BattleAI_GetWantedBattler(gAIScriptPtr[1])); - gAIScriptPtr += 2; -} - -static void Cmd_get_considered_move(void) -{ - AI_THINKING_STRUCT->funcResult = AI_THINKING_STRUCT->moveConsidered; - gAIScriptPtr += 1; -} - -static void Cmd_get_considered_move_effect(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect; - gAIScriptPtr += 1; -} - -static void Cmd_get_ability(void) -{ - //AI_THINKING_STRUCT->funcResult = AI_GetAbility(BattleAI_GetWantedBattler(gAIScriptPtr[1]), TRUE); - gAIScriptPtr += 2; -} - -static void Cmd_check_ability(void) -{ - /*u32 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 ability = AI_GetAbility(battlerId, FALSE); - - if (ability == -1) - AI_THINKING_STRUCT->funcResult = 2; // Unable to answer. - else if (ability == gAIScriptPtr[2]) - AI_THINKING_STRUCT->funcResult = 1; // Pokemon has the ability we wanted to check. - else - AI_THINKING_STRUCT->funcResult = 0; // Pokemon doesn't have the ability we wanted to check. - - gAIScriptPtr += 3;*/ -} - -static void Cmd_get_highest_type_effectiveness(void) -{ - s32 i; - - gMoveResultFlags = 0; - AI_THINKING_STRUCT->funcResult = 0; - for (i = 0; i < MAX_MON_MOVES; i++) - { - gCurrentMove = gBattleMons[sBattler_AI].moves[i]; - if (gCurrentMove != MOVE_NONE) - { - u32 effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, sBattler_AI, gBattlerTarget); - - switch (effectivenessMultiplier) - { - case UQ_4_12(0.0): - default: - gBattleMoveDamage = AI_EFFECTIVENESS_x0; - break; - case UQ_4_12(0.25): - gBattleMoveDamage = AI_EFFECTIVENESS_x0_25; - break; - case UQ_4_12(0.5): - gBattleMoveDamage = AI_EFFECTIVENESS_x0_5; - break; - case UQ_4_12(1.0): - gBattleMoveDamage = AI_EFFECTIVENESS_x1; - break; - case UQ_4_12(2.0): - gBattleMoveDamage = AI_EFFECTIVENESS_x2; - break; - case UQ_4_12(4.0): - gBattleMoveDamage = AI_EFFECTIVENESS_x4; - break; - } - - if (AI_THINKING_STRUCT->funcResult < gBattleMoveDamage) - AI_THINKING_STRUCT->funcResult = gBattleMoveDamage; - } - } - - gAIScriptPtr += 1; -} - -static void Cmd_if_type_effectiveness(void) -{ - // AI_GetMoveEffectiveness -} - -static void Cmd_nullsub_32(void) -{ -} - -static void Cmd_nullsub_33(void) -{ -} - -static void Cmd_if_status_in_party(void) -{ - struct Pokemon *party; - s32 i; - u32 statusToCompareTo; - u8 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - party = (GetBattlerSide(battlerId) == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; - - statusToCompareTo = T1_READ_32(gAIScriptPtr + 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) - { - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - return; - } - } - - gAIScriptPtr += 10; -} - -static void Cmd_if_status_not_in_party(void) -{ - struct Pokemon *party; - s32 i; - u32 statusToCompareTo; - u8 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - party = (GetBattlerSide(battlerId) == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; - - statusToCompareTo = T1_READ_32(gAIScriptPtr + 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) - { - gAIScriptPtr += 10; - return; - } - } - - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); -} - -static void Cmd_get_weather(void) -{ - if (gBattleWeather & WEATHER_RAIN_ANY) - AI_THINKING_STRUCT->funcResult = AI_WEATHER_RAIN; - else if (gBattleWeather & WEATHER_SANDSTORM_ANY) - AI_THINKING_STRUCT->funcResult = AI_WEATHER_SANDSTORM; - else if (gBattleWeather & WEATHER_SUN_ANY) - AI_THINKING_STRUCT->funcResult = AI_WEATHER_SUN; - else if (gBattleWeather & WEATHER_HAIL_ANY) - AI_THINKING_STRUCT->funcResult = AI_WEATHER_HAIL; - else - AI_THINKING_STRUCT->funcResult = AI_WEATHER_NONE; - - gAIScriptPtr += 1; -} - -static void Cmd_if_effect(void) -{ - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect == T1_READ_16(gAIScriptPtr + 1)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_not_effect(void) -{ - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect != T1_READ_16(gAIScriptPtr + 1)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_stat_level_less_than(void) -{ - u32 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - if (gBattleMons[battlerId].statStages[gAIScriptPtr[2]] < gAIScriptPtr[3]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void Cmd_if_stat_level_more_than(void) -{ - u32 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - if (gBattleMons[battlerId].statStages[gAIScriptPtr[2]] > gAIScriptPtr[3]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void Cmd_if_stat_level_equal(void) -{ - u32 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - if (gBattleMons[battlerId].statStages[gAIScriptPtr[2]] == gAIScriptPtr[3]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void Cmd_if_stat_level_not_equal(void) -{ - u32 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - if (gBattleMons[battlerId].statStages[gAIScriptPtr[2]] != gAIScriptPtr[3]) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void Cmd_if_can_faint(void) -{ - s32 dmg; - - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power == 0) - { - gAIScriptPtr += 5; - return; - } - - dmg = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][AI_THINKING_STRUCT->movesetIndex]; - if (gBattleMons[gBattlerTarget].hp <= dmg) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void Cmd_if_cant_faint(void) -{ - s32 dmg; - - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) - { - gAIScriptPtr += 5; - return; - } - - dmg = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][AI_THINKING_STRUCT->movesetIndex]; - if (gBattleMons[gBattlerTarget].hp > dmg) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void Cmd_if_has_move(void) -{ - s32 i; - const u16 *movePtr = (u16 *)(gAIScriptPtr + 2); - - switch (gAIScriptPtr[1]) - { - case AI_USER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[sBattler_AI].moves[i] == *movePtr) - break; - } - if (i == MAX_MON_MOVES) - gAIScriptPtr += 8; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - break; - case AI_USER_PARTNER: - if (gBattleMons[sBattler_AI ^ BIT_FLANK].hp == 0) - { - gAIScriptPtr += 8; - break; - } - else - { - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[sBattler_AI ^ BIT_FLANK].moves[i] == *movePtr) - break; - } - } - if (i == MAX_MON_MOVES) - gAIScriptPtr += 8; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget][i] == *movePtr) - break; - } - if (i == MAX_MON_MOVES) - gAIScriptPtr += 8; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - break; - } -} - -static void Cmd_if_doesnt_have_move(void) -{ - s32 i; - const u16 *movePtr = (u16 *)(gAIScriptPtr + 2); - - switch(gAIScriptPtr[1]) - { - case AI_USER: - case AI_USER_PARTNER: // UB: no separate check for user partner. - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[sBattler_AI].moves[i] == *movePtr) - break; - } - if (i != MAX_MON_MOVES) - gAIScriptPtr += 8; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget][i] == *movePtr) - break; - } - if (i != MAX_MON_MOVES) - gAIScriptPtr += 8; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - break; - } -} - -static void Cmd_if_has_move_with_effect(void) -{ - s32 i; - - switch (gAIScriptPtr[1]) - { - case AI_USER: - case AI_USER_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[sBattler_AI].moves[i] != 0 && gBattleMoves[gBattleMons[sBattler_AI].moves[i]].effect == gAIScriptPtr[2]) - break; - } - if (i == MAX_MON_MOVES) - gAIScriptPtr += 7; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleMons[gBattlerTarget].moves[i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[gBattlerTarget][i]].effect == gAIScriptPtr[2]) - break; - } - if (i == MAX_MON_MOVES) - gAIScriptPtr += 7; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - break; - } -} - -static void Cmd_if_doesnt_have_move_with_effect(void) -{ - s32 i; - - switch (gAIScriptPtr[1]) - { - case AI_USER: - case AI_USER_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if(gBattleMons[sBattler_AI].moves[i] != 0 && gBattleMoves[gBattleMons[sBattler_AI].moves[i]].effect == gAIScriptPtr[2]) - break; - } - if (i != MAX_MON_MOVES) - gAIScriptPtr += 7; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (BATTLE_HISTORY->usedMoves[gBattlerTarget][i] && gBattleMoves[BATTLE_HISTORY->usedMoves[gBattlerTarget][i]].effect == gAIScriptPtr[2]) - break; - } - if (i != MAX_MON_MOVES) - gAIScriptPtr += 7; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - break; - } -} - -static void Cmd_if_any_move_disabled_or_encored(void) -{ - u8 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - if (gAIScriptPtr[2] == 0) - { - if (gDisableStructs[battlerId].disabledMove == MOVE_NONE) - gAIScriptPtr += 7; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - } - else if (gAIScriptPtr[2] != 1) - { - gAIScriptPtr += 7; - } - else - { - if (gDisableStructs[battlerId].encoredMove != MOVE_NONE) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; - } -} - -static void Cmd_if_curr_move_disabled_or_encored(void) -{ - switch (gAIScriptPtr[1]) - { - case 0: - if (gDisableStructs[gActiveBattler].disabledMove == AI_THINKING_STRUCT->moveConsidered) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; - break; - case 1: - if (gDisableStructs[gActiveBattler].encoredMove == AI_THINKING_STRUCT->moveConsidered) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; - break; - default: - gAIScriptPtr += 6; - break; - } -} - -static void Cmd_flee(void) -{ - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); -} - -static void Cmd_if_random_safari_flee(void) -{ - u8 safariFleeRate = gBattleStruct->safariEscapeFactor * 5; // Safari flee rate, from 0-20. - - if ((u8)(Random() % 100) < safariFleeRate) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void Cmd_watch(void) -{ - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); -} - -static void Cmd_get_hold_effect(void) -{ - // AI_GetHoldEffect -} - -static void Cmd_if_holds_item(void) -{ - u8 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u16 item; - - if ((battlerId & BIT_SIDE) == (sBattler_AI & BIT_SIDE)) - item = gBattleMons[battlerId].item; - else - item = BATTLE_HISTORY->itemEffects[battlerId]; - - if (T1_READ_16(gAIScriptPtr + 2) == item) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void Cmd_get_gender(void) -{ - u8 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerId].species, gBattleMons[battlerId].personality); - - gAIScriptPtr += 2; -} - -static void Cmd_is_first_turn_for(void) -{ - u8 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = gDisableStructs[battlerId].isFirstTurn; - - gAIScriptPtr += 2; -} - -static void Cmd_get_stockpile_count(void) -{ - u8 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = gDisableStructs[battlerId].stockpileCounter; - - gAIScriptPtr += 2; -} - -static void Cmd_is_double_battle(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleTypeFlags & BATTLE_TYPE_DOUBLE; - - gAIScriptPtr += 1; -} - -static void Cmd_get_used_held_item(void) -{ - u8 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = gBattleStruct->usedHeldItems[battlerId]; - - gAIScriptPtr += 2; -} - -static void Cmd_get_move_type_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].type; - - gAIScriptPtr += 1; -} - -static void Cmd_get_move_power_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].power; - - gAIScriptPtr += 1; -} - -static void Cmd_get_move_effect_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].effect; - - gAIScriptPtr += 1; -} - -static void Cmd_get_protect_count(void) -{ - u8 battlerId; - - if (gAIScriptPtr[1] == AI_USER) - battlerId = sBattler_AI; - else - battlerId = gBattlerTarget; - - AI_THINKING_STRUCT->funcResult = gDisableStructs[battlerId].protectUses; - - gAIScriptPtr += 2; -} - -static void Cmd_if_move_flag(void) -{ - u32 flag = T1_READ_32(gAIScriptPtr + 1); - - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].flags & flag) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void Cmd_if_field_status(void) -{ - u32 fieldFlags = T1_READ_32(gAIScriptPtr + 1); - - if (gFieldStatuses & fieldFlags) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void Cmd_get_move_accuracy(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].accuracy; - - gAIScriptPtr++; -} - -static void Cmd_call_if_eq(void) -{ - if (AI_THINKING_STRUCT->funcResult == T1_READ_16(gAIScriptPtr + 1)) - { - AIStackPushVar(gAIScriptPtr + 7); - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - } - else - { - gAIScriptPtr += 7; - } -} - -static void Cmd_call_if_move_flag(void) -{ - u32 flag = T1_READ_32(gAIScriptPtr + 1); - - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].flags & flag) - { - AIStackPushVar(gAIScriptPtr + 9); - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); - } - else - { - gAIScriptPtr += 9; - } -} - -static void Cmd_nullsub_57(void) -{ -} - -static void Cmd_call(void) -{ - AIStackPushVar(gAIScriptPtr + 5); - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); -} - -static void Cmd_goto(void) -{ - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); -} - -static void Cmd_end(void) -{ - if (AIStackPop() == 0) - AI_THINKING_STRUCT->aiAction |= AI_ACTION_DONE; -} - -static void Cmd_if_level_cond(void) -{ - switch (gAIScriptPtr[1]) - { - case 0: // greater than - if (gBattleMons[sBattler_AI].level > gBattleMons[gBattlerTarget].level) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; - break; - case 1: // less than - if (gBattleMons[sBattler_AI].level < gBattleMons[gBattlerTarget].level) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; - break; - case 2: // equal - if (gBattleMons[sBattler_AI].level == gBattleMons[gBattlerTarget].level) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; - break; - } -} - -static void Cmd_if_target_taunted(void) -{ - if (gDisableStructs[gBattlerTarget].tauntTimer != 0) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void Cmd_if_target_not_taunted(void) -{ - if (gDisableStructs[gBattlerTarget].tauntTimer == 0) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void Cmd_if_target_is_ally(void) -{ - if ((sBattler_AI & BIT_SIDE) == (gBattlerTarget & BIT_SIDE)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void Cmd_if_flash_fired(void) -{ - u8 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if (gBattleResources->flags->flags[battlerId] & RESOURCE_FLAG_FLASH_FIRE) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void AIStackPushVar(const u8 *var) -{ - gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = var; -} - -static void AIStackPushVar_cursor(void) -{ - gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = gAIScriptPtr; -} - -static bool8 AIStackPop(void) -{ - if (gBattleResources->AI_ScriptsStack->size != 0) - { - --gBattleResources->AI_ScriptsStack->size; - gAIScriptPtr = gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size]; - return TRUE; - } - else - { - return FALSE; - } -} - -static void Cmd_get_ally_chosen_move(void) -{ - // GetAllyChosenMove -} - -static void Cmd_if_has_no_attacking_moves(void) -{ - s32 i; - u8 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - if (IsBattlerAIControlled(battlerId)) - { - for (i = 0; i < 4; i++) - { - if (gBattleMons[battlerId].moves[i] != 0 && gBattleMoves[gBattleMons[battlerId].moves[i]].power != 0) - break; - } - } - else - { - for (i = 0; i < 4; i++) - { - if (BATTLE_HISTORY->usedMoves[battlerId][i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[battlerId][i]].power != 0) - break; - } - } - - if (i == 4) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_get_hazards_count(void) -{ - u8 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u8 side = GetBattlerSide(battlerId); - - switch (T1_READ_16(gAIScriptPtr + 2)) - { - case EFFECT_SPIKES: - AI_THINKING_STRUCT->funcResult = gSideTimers[side].spikesAmount; - break; - case EFFECT_TOXIC_SPIKES: - AI_THINKING_STRUCT->funcResult = gSideTimers[side].toxicSpikesAmount; - break; - } - - gAIScriptPtr += 4; -} - -static void Cmd_if_doesnt_hold_berry(void) -{ - u8 battlerId = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u16 item; - - if (IsBattlerAIControlled(battlerId)) - item = gBattleMons[battlerId].item; - else - item = BATTLE_HISTORY->itemEffects[battlerId]; - - if (ItemId_GetPocket(item) == POCKET_BERRIES) - gAIScriptPtr += 6; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); -} - -static void Cmd_if_share_type(void) -{ - u8 battler1 = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u8 battler2 = BattleAI_GetWantedBattler(gAIScriptPtr[2]); - - if (DoBattlersShareType(battler1, battler2)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_cant_use_last_resort(void) -{ - u8 battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if (CanUseLastResort(battler)) - gAIScriptPtr += 6; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); -} - -static void Cmd_if_has_move_with_split(void) -{ - if (HasMoveWithSplit(BattleAI_GetWantedBattler(gAIScriptPtr[1]), gAIScriptPtr[2])) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_has_no_move_with_split(void) -{ - if (!HasMoveWithSplit(BattleAI_GetWantedBattler(gAIScriptPtr[1]), gAIScriptPtr[2])) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void Cmd_if_physical_moves_unusable(void) -{ - if (MovesWithSplitUnusable(BattleAI_GetWantedBattler(gAIScriptPtr[1]), BattleAI_GetWantedBattler(gAIScriptPtr[2]), SPLIT_PHYSICAL)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -// Check if target has means to faint ai mon. -static void Cmd_if_ai_can_go_down(void) -{ - // CanTargetFaintAi -} - -static void Cmd_if_cant_use_belch(void) -{ - u32 battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if (gBattleStruct->ateBerry[battler & BIT_SIDE] & gBitTable[gBattlerPartyIndexes[battler]]) - gAIScriptPtr += 6; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); -} - -static void Cmd_if_has_move_with_type(void) -{ - u32 i, moveType, battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u16 *moves = GetMovesArray(battler); - - for (i = 0; i < 4; i++) - { - if (moves[i] == MOVE_NONE) - continue; - - SetTypeBeforeUsingMove(moves[i], battler); - GET_MOVE_TYPE(moves[i], moveType); - if (moveType == gAIScriptPtr[2]) - break; - } - - if (i == 4) - gAIScriptPtr += 7; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); -} - -static void Cmd_if_has_move_with_flag(void) -{ - u32 i, flag, battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u16 *moves = GetMovesArray(battler); - - flag = T1_READ_32(gAIScriptPtr + 2); - for (i = 0; i < 4; i++) - { - if (moves[i] != MOVE_NONE && gBattleMoves[moves[i]].flags & flag) - { - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 6); - return; - } - } - - gAIScriptPtr += 10; -} - -static void Cmd_if_no_move_used(void) -{ - u32 i, battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if (!IsBattlerAIControlled(battler)) - { - for (i = 0; i < 4; i++) - { - if (BATTLE_HISTORY->usedMoves[battler][i] != 0 && BATTLE_HISTORY->usedMoves[battler][i] != 0xFFFF) - { - gAIScriptPtr += 6; - return; - } - } - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - } - else - { - gAIScriptPtr += 6; - } -} - -static void Cmd_if_battler_absent(void) -{ - u32 battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if (!IsBattlerAlive(battler)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_is_grounded(void) -{ - u32 battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - - if (IsBattlerGrounded(battler)) - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void Cmd_get_best_dmg_hp_percent(void) -{ - int i, bestDmg; - - bestDmg = 0; - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gBattleResources->ai->simulatedDmg[sBattler_AI][gBattlerTarget][i] > bestDmg) - bestDmg = gBattleResources->ai->simulatedDmg[sBattler_AI][gBattlerTarget][i]; - } - - gBattleResources->ai->funcResult = (bestDmg * 100) / gBattleMons[gBattlerTarget].maxHP; - gAIScriptPtr++; -} - -static void Cmd_get_curr_dmg_hp_percent(void) -{ - int bestDmg = gBattleResources->ai->simulatedDmg[sBattler_AI][gBattlerTarget][AI_THINKING_STRUCT->movesetIndex]; - - gBattleResources->ai->funcResult = (bestDmg * 100) / gBattleMons[gBattlerTarget].maxHP; - gAIScriptPtr++; -} - -static void Cmd_get_move_split_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = GetBattleMoveSplit(AI_THINKING_STRUCT->funcResult); - gAIScriptPtr += 1; -} - -static void Cmd_get_considered_move_split(void) -{ - AI_THINKING_STRUCT->funcResult = GetBattleMoveSplit(AI_THINKING_STRUCT->moveConsidered); - gAIScriptPtr += 1; -} - -static void Cmd_get_considered_move_target(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].target; - gAIScriptPtr += 1; -} - -static void Cmd_compare_speeds(void) -{ - u8 battler1 = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u8 battler2 = BattleAI_GetWantedBattler(gAIScriptPtr[2]); - AI_THINKING_STRUCT->funcResult = GetWhoStrikesFirst(battler1, battler2, TRUE); - gAIScriptPtr += 3; -} - -static void Cmd_is_wakeup_turn(void) -{ - //IsWakeupTurn -} - -static void Cmd_if_has_move_with_accuracy_lt(void) -{ - u32 i; - u32 battler = BattleAI_GetWantedBattler(gAIScriptPtr[1]); - u32 toCmp = gAIScriptPtr[2]; - u16 *moves = GetMovesArray(battler); - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (moves[i] != MOVE_NONE - && gBattleMoves[moves[i]].effect != EFFECT_OHKO - && gBattleMoves[moves[i]].accuracy > 1 - && gBattleMoves[moves[i]].accuracy < toCmp) - break; - } - - if (i == MAX_MON_MOVES) - gAIScriptPtr += 7; - else - gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 3); -} - - - - -// AI Functions +// AI Score Functions +// AI_FLAG_CHECK_BAD_MOVE - decreases move scores static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // move data @@ -4302,10 +2485,11 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // helping hand check - if (isDoubleBattle && AI_DATA->partnerMove != MOVE_NONE + if (isDoubleBattle + && AI_DATA->partnerMove != MOVE_NONE && gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_HELPING_HAND && IS_MOVE_STATUS(move)) - score -= 10; //Don't use a status move if partner wants to help + score -= 10; // Don't use a status move if partner helping if (score < 0) score = 0; @@ -4357,12 +2541,255 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } -static s16 AI_CheckPartner(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { - //TODO + // move data + u8 moveType = gBattleMoves[move].type; + u16 effect = gBattleMoves[move].effect; + u8 target = gBattleMoves[move].target; + // ally data + u8 battlerAtkPartner = AI_DATA->battlerAtkPartner; + u16 atkPartnerAbility = AI_DATA->atkPartnerAbility; + u16 atkPartnerHoldEffect = AI_DATA->atkPartnerHoldEffect; + bool32 partnerProtecting = (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_PROTECT); + bool32 attackerHasBadAbility = (AI_DATA->atkAbility == ABILITY_TRUANT || AI_DATA->atkAbility == ABILITY_SLOW_START || AI_DATA->atkAbility == ABILITY_DEFEATIST); + bool32 partnerHasBadAbility = (atkPartnerAbility == ABILITY_TRUANT || atkPartnerAbility == ABILITY_SLOW_START || atkPartnerAbility == ABILITY_DEFEATIST); + + if (!IsBattlerAlive(battlerAtkPartner)) + return score; + + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_HELP_PARTNER) + score += 2; + + // partner ability checks + if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) + { + switch (atkPartnerAbility) + { + case ABILITY_VOLT_ABSORB: + break; // handled in AI_HPAware + case ABILITY_MOTOR_DRIVE: + if (moveType == TYPE_ELECTRIC && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED)) + score++; + break; + case ABILITY_LIGHTNING_ROD: + if (moveType == TYPE_ELECTRIC + && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) + score++; + break; + case ABILITY_WATER_ABSORB: + case ABILITY_DRY_SKIN: + break; // handled in AI_HPAware + case ABILITY_STORM_DRAIN: + if (moveType == TYPE_WATER + && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) + score++; + break; + case ABILITY_WATER_COMPACTION: + score -= 10; + break; + case ABILITY_FLASH_FIRE: + if (moveType == TYPE_FIRE + && HasMoveWithType(battlerAtkPartner, TYPE_FIRE) + && !(gBattleResources->flags->flags[battlerAtkPartner] & RESOURCE_FLAG_FLASH_FIRE)) + score++; + break; + case ABILITY_SAP_SIPPER: + if (moveType == TYPE_GRASS + && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) + score++; + break; + case ABILITY_JUSTIFIED: + if (moveType == TYPE_DARK + && !IS_MOVE_STATUS(move) + && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) + && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) + score++; + break; + case ABILITY_RATTLED: + if (!IS_MOVE_STATUS(move) + && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED) + && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) + score++; + break; + case ABILITY_CONTRARY: + if (IsStatLoweringEffect(effect)) + score += 2; + break; + case ABILITY_DEFIANT: + if (IsStatLoweringEffect(effect) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) + score++; + break; + case ABILITY_COMPETITIVE: + if (IsStatLoweringEffect(effect) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) + score++; + break; + } + } // ability checks + + // partner move effects + if (AI_DATA->partnerMove != MOVE_NONE) + { + switch (gBattleMoves[AI_DATA->partnerMove].effect) + { + case EFFECT_PERISH_SONG: + if (!IsBattlerTrapped(battlerDef, TRUE) + && (gBattleMoves[move].effect == EFFECT_MEAN_LOOK + || gBattleMoves[move].effect == EFFECT_TRAP)) + score++; // target not trapped, but ally will trap them so perish song is good + break; + case EFFECT_ALWAYS_CRIT: + if (AI_DATA->atkAbility == ABILITY_ANGER_POINT // ai has anger point + && GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 1 // partner goes first + && CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) + { + // encourage multiple target moves + if (!IsAttackBoostMoveEffect(gBattleMoves[move].effect) + && !IS_MOVE_STATUS(move) + && gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) + score += 3; + } + break; + } // partner move effects + } + + // attacker move effects + switch (gBattleMoves[move].effect) + { + case EFFECT_EVASION_UP: + if (move == MOVE_ACUPRESSURE && !partnerProtecting) + score++; + break; + case EFFECT_PURIFY: + if (gBattleMons[battlerAtkPartner].status1 & STATUS1_ANY) + score++; + break; + case EFFECT_SWAGGER: + if (gBattleMons[battlerAtkPartner].statStages[STAT_ATK] < MAX_STAT_STAGE + && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) + && (!CanBeConfused(battlerAtkPartner, TRUE) + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) + score++; + break; + case EFFECT_FLATTER: + if (gBattleMons[battlerAtkPartner].statStages[STAT_SPATK] < MAX_STAT_STAGE + && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) + && (!CanBeConfused(battlerAtkPartner, TRUE) + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) + score++; + break; + case EFFECT_SANDSTORM: + if (ShouldSetSandstorm(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + score ++; + break; + case EFFECT_RAIN_DANCE: + if (ShouldSetRain(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + score ++; + break; + case EFFECT_SUNNY_DAY: + if (ShouldSetSun(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + score ++; + break; + case EFFECT_HAIL: + if (IsBattlerAlive(battlerAtkPartner) + && ShouldSetHail(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + score += 2; + break; + case EFFECT_BEAT_UP: + if (atkPartnerAbility == ABILITY_JUSTIFIED + && moveType == TYPE_DARK + && !IS_MOVE_STATUS(move) + && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) + && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) + score++; + break; + case EFFECT_HELPING_HAND: + if (AI_DATA->partnerMove != MOVE_NONE + && !partnerProtecting + && !IS_MOVE_STATUS(AI_DATA->partnerMove)) + score++; + break; + case EFFECT_SKILL_SWAP: + if (!partnerProtecting && AI_DATA->atkAbility != AI_DATA->atkPartnerAbility && !attackerHasBadAbility) + { + if (AI_DATA->atkPartnerAbility == ABILITY_TRUANT) + score += 10; + else if (AI_DATA->atkAbility == ABILITY_COMPOUND_EYES + && HasMoveWithLowAccuracy(battlerAtkPartner, FOE(battlerAtkPartner), 90, TRUE, atkPartnerAbility, AI_GetAbility(FOE(battlerAtkPartner)), atkPartnerHoldEffect, AI_GetHoldEffect(FOE(battlerAtkPartner)))) + score += 3; + else + score -= 30; + } + break; + case EFFECT_ROLE_PLAY: + if (!partnerProtecting && attackerHasBadAbility && !partnerHasBadAbility) + score++; + break; + case EFFECT_WORRY_SEED: + case EFFECT_GASTRO_ACID: + case EFFECT_SIMPLE_BEAM: + if (!partnerProtecting && partnerHasBadAbility) + score += 2; + break; + case EFFECT_ENTRAINMENT: + if (!partnerProtecting && partnerHasBadAbility && IsAbilityOfRating(AI_DATA->atkAbility, 0)) + score++; + break; + case EFFECT_SOAK: + if (!partnerProtecting && atkPartnerAbility == ABILITY_WONDER_GUARD + && (gBattleMons[battlerAtkPartner].type1 != TYPE_WATER + || gBattleMons[battlerAtkPartner].type2 != TYPE_WATER + || gBattleMons[battlerAtkPartner].type3 != TYPE_WATER)) + score++; + break; + case EFFECT_MAGNET_RISE: + if (IsBattlerGrounded(battlerAtk) + && (HasMove(battlerAtkPartner, MOVE_EARTHQUAKE) || HasMove(battlerAtkPartner, MOVE_MAGNITUDE)) + && (AI_GetMoveEffectiveness(MOVE_EARTHQUAKE) != AI_EFFECTIVENESS_x0)) // Doesn't resist ground move + score += 2; + break; + case EFFECT_INSTRUCT: + if (!partnerProtecting) + { + u16 instructedMove; + if (GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 0) + instructedMove = AI_DATA->partnerMove; + else + instructedMove = gLastMoves[battlerAtkPartner]; + + if (instructedMove != MOVE_NONE + && !IS_MOVE_STATUS(instructedMove) + && gBattleMoves[instructedMove].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) //Use instruct on multi-target moves + { + score++; + } + } + case EFFECT_AFTER_YOU: + if (GetWhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), TRUE) == 1 // opponent mon 1 goes before partner + || GetWhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), TRUE) == 1) // opponent mon 2 goes before partner + { + if (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_COUNTER || gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_MIRROR_COAT) + break; // These moves need to go last + + score++; + } + break; + } // attacker move effects + return score; } +// AI_FLAG_CHECK_GOOD_MOVE - increases move scores static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // move data @@ -4373,9 +2800,9 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); u32 i; - // targeting partner, check benefits of doing that instead + // Targeting partner, check benefits of doing that instead if (isDoubleBattle && AI_DATA->targetSameSide) - return AI_CheckPartner(battlerAtk, AI_DATA->battlerAtkPartner, move, score); + score = AI_TryOnAlly(battlerAtk, AI_DATA->battlerAtkPartner, move, score); // check move results if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) @@ -5027,9 +3454,10 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; if (AI_DATA->atkHoldEffect == HOLD_EFFECT_SMOOTH_ROCK) score++; - if (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) - && ShouldSetSandstorm(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, AI_DATA->atkPartnerHoldEffect)) - score += 2; + if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) + || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) + || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) + score += 2; } break; case EFFECT_HAIL: @@ -5042,9 +3470,6 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; if (AI_DATA->atkHoldEffect == HOLD_EFFECT_ICY_ROCK) score++; - if (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) - && ShouldSetHail(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, AI_DATA->atkPartnerHoldEffect)) - score += 2; if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) @@ -5057,9 +3482,6 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; if (AI_DATA->atkHoldEffect == HOLD_EFFECT_DAMP_ROCK) score++; - if (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) - && ShouldSetRain(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, AI_DATA->atkPartnerHoldEffect)) - score += 2; if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) @@ -5072,9 +3494,6 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (ShouldSetSun(battlerAtk, AI_DATA->atkAbility, AI_DATA->atkHoldEffect)) { score++; - if (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) - && ShouldSetSun(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, AI_DATA->atkPartnerHoldEffect)) - score += 2; // partner also gets sunlight benefit if (AI_DATA->atkHoldEffect == HOLD_EFFECT_HEAT_ROCK) score++; if (HasMoveWithType(battlerDef, TYPE_WATER) || HasMoveWithType(AI_DATA->battlerDefPartner, TYPE_WATER)) @@ -6072,49 +4491,20 @@ static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || !HasMoveEffect(battlerAtk, EFFECT_BATON_PASS) || IsBattlerTrapped(battlerAtk, TRUE)) return score; - - switch (gBattleMoves[move].effect) + + if (IsStatRaisingEffect(gBattleMoves[move].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_CHARGE: - 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: if (gBattleResults.battleTurnCounter == 0) score += 5; else if (GetHealthPercentage(battlerAtk) < 60) score -= 10; else - score++; - break; + score++; + } + + // other specific checks + switch (gBattleMoves[move].effect) + { case EFFECT_INGRAIN: if (!(gStatuses3[battlerAtk] & STATUS3_ROOTED)) score += 2; @@ -6146,13 +4536,186 @@ static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } -static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) -{ - return score; -} - static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { + u16 effect = gBattleMoves[move].effect; + u8 moveType = gBattleMoves[move].type; + + if (IsTargetingPartner(battlerAtk, battlerDef)) + { + if ((effect == EFFECT_HEAL_PULSE || effect == EFFECT_HIT_ENEMY_HEAL_ALLY) + || (moveType == TYPE_ELECTRIC && AI_DATA->atkPartnerAbility == ABILITY_VOLT_ABSORB) + || (moveType == TYPE_WATER && (AI_DATA->atkPartnerAbility == ABILITY_DRY_SKIN || AI_DATA->atkPartnerAbility == ABILITY_WATER_ABSORB))) + { + if (CanTargetFaintAi(FOE(battlerAtk), AI_DATA->battlerAtkPartner) + || (CanTargetFaintAi(BATTLE_PARTNER(FOE(battlerAtk)), AI_DATA->battlerAtkPartner))) + score--; + + if (GetHealthPercentage(battlerDef) <= 50) + score++; + } + } + else + { + // Consider AI HP + if (GetHealthPercentage(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: + case EFFECT_OVERHEAT: + score -= 2; + break; + default: + break; + } + } + else if (GetHealthPercentage(battlerAtk) > 30) + { + // med hp + if (IsStatRaisingEffect(effect) || IsStatLoweringEffect(effect)) + 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: + score -= 2; + break; + default: + break; + } + } + else + { + // low hp + if (IsStatRaisingEffect(effect) || IsStatLoweringEffect(effect)) + 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_SOLARBEAM: + case EFFECT_TWO_TURNS_ATTACK: + case EFFECT_ERUPTION: + case EFFECT_TICKLE: + case EFFECT_SUNNY_DAY: + case EFFECT_SANDSTORM: + case EFFECT_HAIL: + case EFFECT_RAIN_DANCE: + score -= 2; + break; + default: + break; + } + } + } + + // consider target HP + if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + { + score += 2; + } + else + { + if (GetHealthPercentage(battlerDef) > 70) + { + // high HP + ; // nothing yet + } + else if (GetHealthPercentage(battlerDef) > 30) + { + // med HP - check discouraged effects + switch (effect) + { + case EFFECT_ATTACK_UP: + 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: + score -= 2; + break; + default: + break; + } + } + else + { + // low HP + if (IS_MOVE_STATUS(move)) + score -= 2; // don't use status moves if target is at low health + } + } + return score; } @@ -6197,13 +4760,3 @@ static s16 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } - - - - - - - - - - diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 9002eaefe8..0bd00de65b 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -1,6 +1,6 @@ #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" diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 485d179fe4..753360e3cc 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3,7 +3,7 @@ #include "battle.h" #include "battle_anim.h" #include "battle_ai_util.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_ai_switch_items.h" #include "battle_factory.h" #include "battle_setup.h" @@ -603,6 +603,31 @@ bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch) return FALSE; } +u32 GetTotalBaseStat(u32 species) +{ + return gBaseStats[species].baseHP + + gBaseStats[species].baseAttack + + gBaseStats[species].baseDefense + + gBaseStats[species].baseSpeed + + gBaseStats[species].baseSpAttack + + gBaseStats[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 (gBattleMoves[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE) + return TRUE; + if (gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAI, opposingBattler, TRUE) == 1) + return TRUE; + } + return FALSE; +} + // move checks bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect) { @@ -1028,15 +1053,15 @@ u16 AI_GetHoldEffect(u32 battlerId) else holdEffect = GetBattlerHoldEffect(battlerId, FALSE); - if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_AWARE) - { - if (gStatuses3[battlerId] & STATUS3_EMBARGO) - return HOLD_EFFECT_NONE; - if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) - return HOLD_EFFECT_NONE; - if (AI_GetAbility(battlerId) == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) - return HOLD_EFFECT_NONE; - } + if (AI_THINKING_STRUCT->aiFlags & 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_GetAbility(battlerId) == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) + return HOLD_EFFECT_NONE; } // different from IsBattlerGrounded in that we don't always know battler's hold effect or ability @@ -1070,7 +1095,7 @@ bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move) { u32 i; - if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_AWARE)) + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return FALSE; // AI doesn't understand ability suppression concept for (i = 0; i < ARRAY_COUNT(sIgnoreMoldBreakerMoves); i++) @@ -1089,7 +1114,7 @@ bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move) bool32 AI_WeatherHasEffect(void) { - if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_AWARE)) + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return FALSE; // AI doesn't understand ability suppression concept return WEATHER_HAS_EFFECT; @@ -1183,7 +1208,7 @@ bool32 IsHazardMoveEffect(u16 moveEffect) bool32 IsMoveRedirectionPrevented(u16 move, u16 atkAbility) { - if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_AWARE)) + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return FALSE; if (move == MOVE_SKY_DROP @@ -1844,6 +1869,95 @@ bool32 HasThawingMove(u8 battlerId) return FALSE; } +bool32 IsAttackBoostMoveEffect(u16 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: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsStatRaisingEffect(u16 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_CHARGE: + 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: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsStatLoweringEffect(u16 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: + return TRUE; + default: + return FALSE; + } +} + bool32 HasDamagingMove(u8 battlerId) { u32 i; @@ -2438,11 +2552,18 @@ bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u1 return TRUE; } +bool32 CanBeConfused(u8 battler, u16 ability) +{ + if ((gBattleMons[battler].status2 & STATUS2_CONFUSION) + || (ability == ABILITY_OWN_TEMPO) + || (IsBattlerGrounded(battler) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN))) + return FALSE; + return TRUE; +} + bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) { - if ((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) - || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && defAbility == ABILITY_OWN_TEMPO) - || (IsBattlerGrounded(battlerDef) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + if (CanBeConfused(battlerDef, defAbility) || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) diff --git a/src/battle_controller_link_opponent.c b/src/battle_controller_link_opponent.c index a9e153cd93..c8a32aaa9a 100644 --- a/src/battle_controller_link_opponent.c +++ b/src/battle_controller_link_opponent.c @@ -1,6 +1,6 @@ #include "global.h" #include "battle.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_interface.h" diff --git a/src/battle_controller_link_partner.c b/src/battle_controller_link_partner.c index 2f0929f257..6280ee2432 100644 --- a/src/battle_controller_link_partner.c +++ b/src/battle_controller_link_partner.c @@ -1,6 +1,6 @@ #include "global.h" #include "battle.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_interface.h" diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 78765a3867..aa91f7c8cb 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -1,6 +1,6 @@ #include "global.h" #include "battle.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_anim.h" #include "battle_arena.h" #include "battle_controllers.h" diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index 9743e92e00..40848ad9dc 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -1,6 +1,6 @@ #include "global.h" #include "battle.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_message.h" diff --git a/src/battle_controller_recorded_opponent.c b/src/battle_controller_recorded_opponent.c index 3480cda921..571d5ac885 100644 --- a/src/battle_controller_recorded_opponent.c +++ b/src/battle_controller_recorded_opponent.c @@ -1,6 +1,6 @@ #include "global.h" #include "battle.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_interface.h" diff --git a/src/battle_controller_recorded_player.c b/src/battle_controller_recorded_player.c index c26b421fa5..3026e5007c 100644 --- a/src/battle_controller_recorded_player.c +++ b/src/battle_controller_recorded_player.c @@ -1,6 +1,6 @@ #include "global.h" #include "battle.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_message.h" diff --git a/src/battle_controllers.c b/src/battle_controllers.c index eb6d73ba78..b819fb5ea4 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -1,6 +1,6 @@ #include "global.h" #include "battle.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_message.h" diff --git a/src/battle_debug.c b/src/battle_debug.c index 05e6c9ef24..bc17cafb3a 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -18,7 +18,8 @@ #include "text_window.h" #include "international_string_util.h" #include "strings.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" +#include "battle_ai_util.h" #include "list_menu.h" #include "decompress.h" #include "trainer_pokemon_sprites.h" diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 3d7222ffe8..f2a3279938 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -1,7 +1,7 @@ #include "global.h" #include "battle.h" #include "battle_controllers.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_anim.h" #include "constants/battle_anim.h" #include "battle_interface.h" diff --git a/src/battle_main.c b/src/battle_main.c index b46527b80c..448685a5a0 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -1,7 +1,7 @@ #include "global.h" #include "battle.h" #include "battle_anim.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_ai_util.h" #include "battle_arena.h" #include "battle_controllers.h" diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index a72feb87c5..a7b961bdaa 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -4,7 +4,7 @@ #include "constants/battle_script_commands.h" #include "battle_message.h" #include "battle_anim.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_ai_util.h" #include "battle_scripts.h" #include "constants/moves.h" diff --git a/src/battle_util.c b/src/battle_util.c index 40260bbe15..873141221e 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -23,7 +23,7 @@ #include "trig.h" #include "window.h" #include "battle_message.h" -#include "battle_ai_script_commands.h" +#include "battle_ai_main.h" #include "battle_ai_util.h" #include "event_data.h" #include "link.h" diff --git a/src/battle_util2.c b/src/battle_util2.c index 55f710a77c..dbd9d66c6b 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -26,7 +26,6 @@ void AllocateBattleResources(void) gBattleResources->beforeLvlUp = AllocZeroed(sizeof(*gBattleResources->beforeLvlUp)); gBattleResources->ai = AllocZeroed(sizeof(*gBattleResources->ai)); 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); @@ -58,7 +57,6 @@ void FreeBattleResources(void) FREE_AND_SET_NULL(gBattleResources->beforeLvlUp); FREE_AND_SET_NULL(gBattleResources->ai); FREE_AND_SET_NULL(gBattleResources->battleHistory); - FREE_AND_SET_NULL(gBattleResources->AI_ScriptsStack); FREE_AND_SET_NULL(gBattleResources); FREE_AND_SET_NULL(gLinkBattleSendBuffer); diff --git a/sym_ewram.txt b/sym_ewram.txt index 88c4461cb0..59829eff49 100644 --- a/sym_ewram.txt +++ b/sym_ewram.txt @@ -91,7 +91,7 @@ .include "src/region_map.o" .include "src/decoration.o" .include "src/slot_machine.o" - .include "src/battle_ai_script_commands.o" + .include "src/battle_ai_main.o" .include "src/fldeff_misc.o" .include "src/pokeblock.o" .include "src/field_specials.o" From 62fc47881db33946ca2e3bf15d5b8322a862050c Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 20 Dec 2020 15:10:57 -0700 Subject: [PATCH 13/36] smaller score bonus to speed increase --- src/battle_ai_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 753360e3cc..381a90c4be 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3238,7 +3238,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) break; case STAT_SPEED: if (IsAiFaster(AI_CHECK_SLOWER)) - *score += 3; + *score += 2; break; case STAT_SPATK: if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && GetHealthPercentage(battlerAtk) > 40) From 19b1d4bfa23f56bf1f15d1333d10c1b7d0a519ae Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 20 Dec 2020 15:15:33 -0700 Subject: [PATCH 14/36] speed stat increases based on current stat stage --- src/battle_ai_util.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 381a90c4be..510da52b91 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3238,7 +3238,12 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) break; case STAT_SPEED: if (IsAiFaster(AI_CHECK_SLOWER)) - *score += 2; + { + if (gBattleMons[battlerAtk].statStages[STAT_SPEED] < STAT_UP_2_STAGE) + *score += 2; + else if (gBattleMons[battlerAtk].statStages[STAT_SPEED] < STAT_UP_STAGE) + *(score)++; + } break; case STAT_SPATK: if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && GetHealthPercentage(battlerAtk) > 40) From 1ae57f26a37f1469e59ceb920df4a28e40399a29 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 4 Jan 2021 15:30:02 -0700 Subject: [PATCH 15/36] fix up some negative checks, organize some effects in AI_CheckBadMove --- include/battle_ai_main.h | 13 + include/battle_ai_util.h | 3 +- src/battle_ai_main.c | 1650 ++++++++++++++++++-------------------- src/battle_ai_util.c | 101 ++- 4 files changed, 863 insertions(+), 904 deletions(-) diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index 52da9359a0..66c614f78c 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -7,6 +7,19 @@ #define AI_CHOICE_WATCH 5 #define AI_CHOICE_SWITCH 7 +#define RETURN_SCORE_PLUS(val) \ +{ \ + score += val; \ + return score; \ +} + +#define RETURN_SCORE_MINUS(val) \ +{ \ + score -= val; \ + return score; \ +} + + void BattleAI_SetupItems(void); void BattleAI_SetupFlags(void); void BattleAI_SetupAIData(u8 defaultScoreMoves); diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 428e47e23c..6ecebc03ec 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -55,13 +55,12 @@ s8 GetAbilityRating(u16 ability); // stat stage checks bool32 AnyStatIsRaised(u8 battlerId); -bool32 BattlerStatCanFall(u8 battler, u16 battlerAbility, u8 stat); +bool32 ShouldLowerStat(u8 battler, u16 battlerAbility, u8 stat); bool32 BattlerStatCanRise(u8 battler, u16 battlerAbility, u8 stat); bool32 AreBattlersStatsMaxed(u8 battler); bool32 BattlerHasAnyStatRaised(u8 battlerId); u32 CountPositiveStatStages(u8 battlerId); u32 CountNegativeStatStages(u8 battlerId); -bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability); bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index ec23986298..dce550fcf8 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -57,6 +57,7 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = { @@ -67,7 +68,7 @@ static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = [4] = AI_Risky, // AI_FLAG_RISKY [5] = AI_PreferStrongestMove, // AI_FLAG_PREFER_STRONGEST_MOVE [6] = AI_PreferBatonPass, // AI_FLAG_PREFER_BATON_PASS - [7] = NULL, // AI_FLAG_DOUBLE_BATTLE. split between AI_CheckBadMove & AI_CheckGoodMove + [7] = AI_TryOnAlly, // AI_FLAG_DOUBLE_BATTLE. [8] = AI_HPAware, // AI_FLAG_HP_AWARE [9] = NULL, // AI_FLAG_NEGATE_UNAWARE [10] = NULL, // AI_FLAG_WILL_SUICIDE @@ -232,7 +233,6 @@ static void GetAiLogicData(u8 battlerAtk, u8 battlerDef) AI_DATA->partnerMove = GetAllyChosenMove(); AI_DATA->atkPartnerAbility = AI_GetAbility(AI_DATA->battlerAtkPartner); AI_DATA->atkPartnerHoldEffect = AI_GetHoldEffect(AI_DATA->battlerAtkPartner); - AI_DATA->targetSameSide = IsTargetingPartner(battlerAtk, battlerDef); // target partner data AI_DATA->battlerDefPartner = BATTLE_PARTNER(battlerDef); AI_DATA->defPartnerAbility = AI_GetAbility(AI_DATA->battlerDefPartner); @@ -516,13 +516,15 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u8 moveTarget = gBattleMoves[move].target; u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); u8 effectiveness = AI_GetMoveEffectiveness(move); + u8 typeEffectiveness = AI_GetTypeEffectiveness(move, battlerAtk, battlerDef); bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); u32 i; u16 predictedMove = gLastMoves[battlerDef]; // TODO better move prediction - if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HELP_PARTNER) && AI_DATA->targetSameSide) - return score; // don't consider ally presence + if (IsTargetingPartner(battlerAtk, battlerDef)) + return score; + // check non-user target if (!(gBattleMoves[move].target & MOVE_TARGET_USER)) { // handle negative checks on non-user target @@ -546,8 +548,8 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // check if negates type - if (effectiveness == AI_EFFECTIVENESS_x0) - score -= 20; + if (!IS_MOVE_STATUS(move) && (effectiveness == AI_EFFECTIVENESS_x0 || typeEffectiveness == AI_EFFECTIVENESS_x0)) + score -= 10; // target ability checks if (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) @@ -557,101 +559,100 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case ABILITY_VOLT_ABSORB: case ABILITY_MOTOR_DRIVE: case ABILITY_LIGHTNING_ROD: - if (moveType == TYPE_ELECTRIC && !IsTargetingPartner(battlerAtk, battlerDef)) - score -= 20; + if (moveType == TYPE_ELECTRIC) + RETURN_SCORE_MINUS(20); break; case ABILITY_WATER_ABSORB: case ABILITY_DRY_SKIN: case ABILITY_STORM_DRAIN: - if (moveType == TYPE_WATER && !IsTargetingPartner(battlerAtk, battlerDef)) - score -= 20; + if (moveType == TYPE_WATER) + RETURN_SCORE_MINUS(20); break; case ABILITY_FLASH_FIRE: - if (moveType == TYPE_FIRE && !IsTargetingPartner(battlerAtk, battlerDef)) - score -= 20; + if (moveType == TYPE_FIRE) + RETURN_SCORE_MINUS(20); break; case ABILITY_WONDER_GUARD: if (effectiveness != AI_EFFECTIVENESS_x2 && effectiveness != AI_EFFECTIVENESS_x4) return 0; break; case ABILITY_SAP_SIPPER: - if (moveType == TYPE_GRASS && !IsTargetingPartner(battlerAtk, battlerDef)) - score -= 20; + if (moveType == TYPE_GRASS) + RETURN_SCORE_MINUS(20); break; case ABILITY_JUSTIFIED: - if (moveType == TYPE_DARK && !IS_MOVE_STATUS(move) && !IsTargetingPartner(battlerAtk, battlerDef)) - score -= 10; + 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) - && !IsTargetingPartner(battlerAtk, battlerDef)) - score -= 10; + && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG)) + RETURN_SCORE_MINUS(10); break; case ABILITY_SOUNDPROOF: if (TestMoveFlags(move, FLAG_SOUND)) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_BULLETPROOF: if (TestMoveFlags(move, FLAG_BALLISTIC)) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_DAZZLING: case ABILITY_QUEENLY_MAJESTY: if (atkPriority > 0) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_AROMA_VEIL: if (IsAromaVeilProtectedMove(move)) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_SWEET_VEIL: if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_FLOWER_VEIL: if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) && (IsNonVolatileStatusMoveEffect(moveEffect) || IsStatLoweringMoveEffect(moveEffect))) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_MAGIC_BOUNCE: if (TestMoveFlags(move, FLAG_MAGICCOAT_AFFECTED)) - score -= 20; + RETURN_SCORE_MINUS(20); break; case ABILITY_CONTRARY: - if (IsStatLoweringMoveEffect(moveEffect) && !IsTargetingPartner(battlerAtk, battlerDef)) - score -= 20; + if (IsStatLoweringMoveEffect(moveEffect)) + RETURN_SCORE_MINUS(20); break; case ABILITY_CLEAR_BODY: - //case ABILITY_FULL_METAL_BODY: // maybe? + case ABILITY_FULL_METAL_BODY: case ABILITY_WHITE_SMOKE: if (IsStatLoweringMoveEffect(moveEffect)) - score -= 10; + 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) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_KEEN_EYE: if (moveEffect == EFFECT_ACCURACY_DOWN || moveEffect == EFFECT_ACCURACY_DOWN_2) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_BIG_PECKS: if (moveEffect == EFFECT_DEFENSE_DOWN || moveEffect == EFFECT_DEFENSE_DOWN_2) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_DEFIANT: case ABILITY_COMPETITIVE: if (IsStatLoweringMoveEffect(moveEffect) && !IsTargetingPartner(battlerAtk, battlerDef)) - score -= 8; + RETURN_SCORE_MINUS(8); break; case ABILITY_COMATOSE: if (IsNonVolatileStatusMoveEffect(moveEffect)) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_SHIELDS_DOWN: if (IsShieldsDownProtected(battlerAtk) && IsNonVolatileStatusMoveEffect(moveEffect)) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_WONDER_SKIN: if (IS_MOVE_STATUS(move)) @@ -661,71 +662,75 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (AI_WeatherHasEffect() && (gBattleWeather & WEATHER_SUN_ANY) && AI_DATA->defHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA && IsNonVolatileStatusMoveEffect(moveEffect)) - score -= 10; + RETURN_SCORE_MINUS(10); break; } // def ability checks - // target partner ability checks - if (isDoubleBattle && !IsTargetingPartner(battlerAtk, battlerDef)) + // target partner ability checks & not attacking partner + if (isDoubleBattle) { switch (AI_DATA->defPartnerAbility) { case ABILITY_LIGHTNING_ROD: if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(move, AI_DATA->atkAbility)) - score -= 20; + RETURN_SCORE_MINUS(20); break; case ABILITY_STORM_DRAIN: if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(move, AI_DATA->atkAbility)) - score -= 20; + RETURN_SCORE_MINUS(20); break; case ABILITY_MAGIC_BOUNCE: if (TestMoveFlags(move, FLAG_MAGICCOAT_AFFECTED) && moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD)) - score -= 20; + RETURN_SCORE_MINUS(20); break; case ABILITY_SWEET_VEIL: if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) - score -= 10; + RETURN_SCORE_MINUS(20); break; case ABILITY_FLOWER_VEIL: if ((IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS)) && (IsNonVolatileStatusMoveEffect(moveEffect) || IsStatLoweringMoveEffect(moveEffect))) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_AROMA_VEIL: if (IsAromaVeilProtectedMove(move)) - score -= 10; + RETURN_SCORE_MINUS(10); break; case ABILITY_DAZZLING: case ABILITY_QUEENLY_MAJESTY: if (atkPriority > 0) - score -= 10; + RETURN_SCORE_MINUS(10); break; } } // def partner ability checks } // ignore def ability check - #if B_PRANKSTER < GEN_7 + // gen7+ dark type mons immune to priority->elevated moves from prankster + #if B_PRANKSTER >= GEN_7 if (AI_DATA->atkAbility == ABILITY_PRANKSTER && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) && IS_MOVE_STATUS(move) && !(moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER))) - score -= 10; + RETURN_SCORE_MINUS(10); #endif - // terrain effect checks + // terrain & effect checks if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) { if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN) - score -= 10; + RETURN_SCORE_MINUS(20); } + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) { if (IsNonVolatileStatusMoveEffect(moveEffect) || IsConfusionMoveEffect(moveEffect)) - score -= 10; + RETURN_SCORE_MINUS(20); } + if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) { if (atkPriority > 0) - score -= 10; - } + RETURN_SCORE_MINUS(20); + } } // end check MOVE_TARGET_USER + // the following checks apply to any target (including user) // throat chop check @@ -742,99 +747,111 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { case EFFECT_HIT: default: - break; + break; // check move damage case EFFECT_SLEEP: - if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - score -= 10; - else if (!AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_ABSORB: - if (AI_DATA->defAbility == ABILITY_LIQUID_OOZE) - score -= 6; - break; - case EFFECT_STRENGTH_SAP: - if (AI_DATA->defAbility == ABILITY_CONTRARY) - score -= 10; - else if (!BattlerStatCanFall(battlerDef, AI_DATA->defAbility, STAT_ATK)) + if (!AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_EXPLOSION: - if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE) + if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE)) + score -= 2; + + if (typeEffectiveness == AI_EFFECTIVENESS_x0) { - if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) - { - score -= 10; - } - else if (CountUsablePartyMons(battlerDef) == 0 && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) - { - ; // target has 1 pkmn left but you can faint it -> good to use - } - else if (isDoubleBattle) - { - if (CountUsablePartyMons(battlerDef) != 0 - && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0) - && CanAttackerFaintTarget(AI_DATA->battlerAtkPartner, BATTLE_PARTNER(battlerDef), *(gBattleStruct->chosenMovePositions + AI_DATA->battlerAtkPartner), 0)) - { - ; // good - } - else - { - score -= 4; - } - } - else - { - if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) - { - if (CountUsablePartyMons(battlerDef) == 0) - { - ; //Good to use move - } - } - else - { - score -= 4; - } - } + score -= 10; } - else + else if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) { - score -= 4; + score -= 10; + } + else if (CountUsablePartyMons(battlerAtk) == 0) + { + if (CountUsablePartyMons(battlerDef) != 0) + score -= 10; + else + score--; } break; case EFFECT_DREAM_EATER: - if (AI_DATA->defAbility != ABILITY_COMATOSE && !(gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) + if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP) || AI_DATA->defAbility == ABILITY_COMATOSE) + score -= 8; + else if (typeEffectiveness == AI_EFFECTIVENESS_x0) score -= 10; break; - case EFFECT_COPYCAT: - case EFFECT_MIRROR_MOVE: - return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); - case EFFECT_TELEPORT: - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) - { - if (CountUsablePartyMons(battlerAtk) == 0) - score -= 10; - } - else if (GetBattlerSide(battlerAtk) == B_SIDE_OPPONENT) - { - if (isDoubleBattle || IsBattlerTrapped(battlerAtk, FALSE)) - score -= 10; - } - break; + // stat raising effects case EFFECT_ATTACK_UP: case EFFECT_ATTACK_UP_2: - if (AI_DATA->atkAbility != ABILITY_CONTRARY) - { - if (MovesWithSplitUnusable(battlerAtk, battlerDef, SPLIT_PHYSICAL)) - score -= 8; - else if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) - score -= 10; - } - else - { + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; - } + break; + case EFFECT_DEFENSE_UP_2: + if (move == MOVE_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[battlerAtk].item) != POCKET_BERRIES) + score -= 10; + //fallthrough + case EFFECT_DEFENSE_UP: + case EFFECT_DEFENSE_UP_3: + case EFFECT_DEFENSE_CURL: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + score -= 10; + break; + case EFFECT_SPEED_UP: + case EFFECT_SPEED_UP_2: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) + score -= 10; + break; + case EFFECT_SPECIAL_ATTACK_UP: + case EFFECT_SPECIAL_ATTACK_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_3: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + score -= 10; + break; + case EFFECT_SPECIAL_DEFENSE_UP: + case EFFECT_SPECIAL_DEFENSE_UP_2: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + score -= 10; + break; + case EFFECT_ACCURACY_UP: + case EFFECT_ACCURACY_UP_2: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ACC)) + score -= 10; + break; + case EFFECT_EVASION_UP: + case EFFECT_EVASION_UP_2: + case EFFECT_MINIMIZE: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_EVASION)) + score -= 10; + break; + case EFFECT_COSMIC_POWER: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + score -= 8; + break; + case EFFECT_BULK_UP: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + score -= 8; + break; + case EFFECT_CALM_MIND: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + score -= 8; + break; + case EFFECT_DRAGON_DANCE: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) + score -= 8; + break; + case EFFECT_COIL: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ACC)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + score -= 8; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + score -= 6; break; case EFFECT_ATTACK_ACCURACY_UP: //hone claws if (AI_DATA->atkAbility != ABILITY_CONTRARY) @@ -849,80 +866,59 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; } break; - case EFFECT_DEFENSE_UP: - case EFFECT_DEFENSE_UP_2: - case EFFECT_DEFENSE_UP_3: - case EFFECT_DEFENSE_CURL: - if (move == MOVE_STUFF_CHEEKS) + case EFFECT_CHARGE: + if (gStatuses3[battlerAtk] & STATUS3_CHARGED_UP) + score -= 20; + else if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + score -= 5; + break; + case EFFECT_QUIVER_DANCE: + case EFFECT_GEOMANCY: + if (gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) + score -= 8; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + score -= 6; + break; + case EFFECT_SHIFT_GEAR: + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) + score -= 8; + break; + case EFFECT_SHELL_SMASH: + if (AI_DATA->atkAbility == ABILITY_CONTRARY) { - if (ItemId_GetPocket(gBattleMons[battlerAtk].item) != POCKET_BERRIES) // AI knows its own item + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + score -= 8; } else { - if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + score -= 8; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) + score -= 6; } break; - case EFFECT_FLOWER_SHIELD: - if (!IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) - && !(isDoubleBattle && IS_BATTLER_OF_TYPE(AI_DATA->battlerAtkPartner, TYPE_GRASS))) - score -= 10; - break; - case EFFECT_MAGNETIC_FLUX: - if (AI_DATA->atkAbility == ABILITY_PLUS || AI_DATA->atkAbility == ABILITY_MINUS) - { - if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE - && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) - score -= 10; - } - else if (!isDoubleBattle) - { - score -= 10; // our stats wont rise from this move - } - - if (isDoubleBattle) - { - if (AI_DATA->atkPartnerAbility == ABILITY_PLUS || AI_DATA->atkPartnerAbility == ABILITY_MINUS) - { - if ((gBattleMons[AI_DATA->battlerAtkPartner].statStages[STAT_DEF] >= MAX_STAT_STAGE) - && (gBattleMons[AI_DATA->battlerAtkPartner].statStages[STAT_SPDEF] >= MAX_STAT_STAGE)) - score -= 10; - } - else if (AI_DATA->atkAbility != ABILITY_PLUS && AI_DATA->atkAbility != ABILITY_MINUS) - { - score -= 10; // nor our or our partner's ability is plus/minus - } - } - break; - case EFFECT_AROMATIC_MIST: - if (!isDoubleBattle || gBattleMons[AI_DATA->battlerAtkPartner].hp == 0 || !BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPDEF)) - score -= 10; - break; - case EFFECT_SPEED_UP: - case EFFECT_SPEED_UP_2: - if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) - score -= 10; - break; - case EFFECT_SPECIAL_ATTACK_UP: - case EFFECT_SPECIAL_ATTACK_UP_2: - case EFFECT_SPECIAL_ATTACK_UP_3: - if (AI_DATA->atkAbility == ABILITY_CONTRARY - || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) - || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) - score -= 10; - break; case EFFECT_GROWTH: case EFFECT_ATTACK_SPATK_UP: // work up - if (!BattlerShouldRaiseAttacks(battlerAtk, AI_DATA->atkAbility)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + score -= 8; break; case EFFECT_ROTOTILLER: if (isDoubleBattle) { if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) && AI_IsBattlerGrounded(battlerAtk) - && AI_DATA->atkAbility != ABILITY_CONTRARY && (BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK))) && !(IS_BATTLER_OF_TYPE(AI_DATA->battlerAtkPartner, TYPE_GRASS) && AI_IsBattlerGrounded(AI_DATA->battlerAtkPartner) @@ -935,7 +931,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) && AI_IsBattlerGrounded(battlerAtk) - && AI_DATA->atkAbility != ABILITY_CONTRARY && (BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK)))) { score -= 10; @@ -944,8 +939,12 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_GEAR_UP: if (AI_DATA->atkAbility == ABILITY_PLUS || AI_DATA->atkAbility == ABILITY_MINUS) { - if (!BattlerShouldRaiseAttacks(battlerAtk, AI_DATA->atkAbility)) + // same as growth, work up + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + score -= 8; + break; } else if (!isDoubleBattle) { @@ -966,77 +965,107 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } } break; - case EFFECT_SPECIAL_DEFENSE_UP: - case EFFECT_SPECIAL_DEFENSE_UP_2: - if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) - score -= 10; - break; - case EFFECT_ACCURACY_UP: - case EFFECT_ACCURACY_UP_2: - if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ACC)) - score -= 10; - break; - case EFFECT_EVASION_UP: - case EFFECT_EVASION_UP_2: - case EFFECT_MINIMIZE: - if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_EVASION)) - score -= 10; - break; case EFFECT_ACUPRESSURE: - if (DoesSubstituteBlockMove(battlerAtk, battlerDef, move) - || AreBattlersStatsMaxed(battlerDef) || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) + if (DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || AreBattlersStatsMaxed(battlerDef)) score -= 10; break; + case EFFECT_MAGNETIC_FLUX: + if (AI_DATA->atkAbility == ABILITY_PLUS || AI_DATA->atkAbility == ABILITY_MINUS) + { + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + score -= 8; + } + else if (!isDoubleBattle) + { + score -= 10; // our stats wont rise from this move + } + + if (isDoubleBattle) + { + if (AI_DATA->atkPartnerAbility == ABILITY_PLUS || AI_DATA->atkPartnerAbility == ABILITY_MINUS) + { + if (!BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_DEF)) + score -= 10; + else if (!BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPDEF)) + score -= 8; + } + else if (AI_DATA->atkAbility != ABILITY_PLUS && AI_DATA->atkAbility != ABILITY_MINUS) + { + 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 (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE - || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL) - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner - { + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) //|| !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) score -= 10; - } - break; - case EFFECT_VENOM_DRENCH: - if (AI_DATA->targetSameSide) + else if (AI_DATA->defAbility == ABILITY_HYPER_CUTTER) score -= 10; - - if (!(gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)) - { - score -= 10; - } - else if (gBattleMons[battlerDef].statStages[STAT_SPEED] == MIN_STAT_STAGE - && (gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) - && (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL))) - { - score -= 10; - } - break; - case EFFECT_NOBLE_ROAR: - if (((gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) - && (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL))) - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner - { - score -= 10; - } break; case EFFECT_DEFENSE_DOWN: case EFFECT_DEFENSE_DOWN_2: - if (gBattleMons[battlerDef].statStages[STAT_DEF] == MIN_STAT_STAGE - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_DEF)) score -= 10; break; case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN_2: - if (gBattleMons[battlerDef].statStages[STAT_SPEED] == MIN_STAT_STAGE - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPEED)) + score -= 10; + else if (AI_DATA->defAbility == ABILITY_SPEED_BOOST) score -= 10; break; case EFFECT_SPECIAL_ATTACK_DOWN: case EFFECT_SPECIAL_ATTACK_DOWN_2: - if (gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPATK)) //|| !HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) score -= 10; break; + case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN_2: + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPDEF)) + score -= 10; + break; + case EFFECT_ACCURACY_DOWN: + case EFFECT_ACCURACY_DOWN_2: + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ACC)) + score -= 10; + else if (AI_DATA->defAbility == ABILITY_KEEN_EYE) + score -= 8; + break; + case EFFECT_EVASION_DOWN: + case EFFECT_EVASION_DOWN_2: + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_EVASION)) + score -= 10; + break; + case EFFECT_TICKLE: + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) + score -= 10; + else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_DEF)) + score -= 8; + break; + case EFFECT_VENOM_DRENCH: + if (!(gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)) + { + score -= 10; + } + else + { + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPEED)) + score -= 10; + else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPATK)) + score -= 8; + else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) + score -= 6; + } + break; + case EFFECT_NOBLE_ROAR: + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPATK)) + score -= 10; + else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) + score -= 8; + break; case EFFECT_CAPTIVATE: { u8 atkGender = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerAtk].species, gBattleMons[battlerAtk].personality); @@ -1045,24 +1074,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; } break; - case EFFECT_SPECIAL_DEFENSE_DOWN: - case EFFECT_SPECIAL_DEFENSE_DOWN_2: - if (gBattleMons[battlerDef].statStages[STAT_SPDEF] == MIN_STAT_STAGE - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner - score -= 10; - break; - case EFFECT_ACCURACY_DOWN: - case EFFECT_ACCURACY_DOWN_2: - if (gBattleMons[battlerDef].statStages[STAT_ACC] == MIN_STAT_STAGE - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner - score -= 10; - break; - case EFFECT_EVASION_DOWN: - case EFFECT_EVASION_DOWN_2: - if (gBattleMons[battlerDef].statStages[STAT_EVASION] == MIN_STAT_STAGE - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner - score -= 10; - break; + // other case EFFECT_HAZE: if (PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) { @@ -1082,27 +1094,460 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } } break; + //case EFFECT_BIDE: + //case EFFECT_SUPER_FANG: + //case EFFECT_RECHARGE: + case EFFECT_LEVEL_DAMAGE: + case EFFECT_PSYWAVE: + //case EFFECT_COUNTER: + //case EFFECT_FLAIL: + case EFFECT_RETURN: + case EFFECT_PRESENT: + case EFFECT_FRUSTRATION: + case EFFECT_SONICBOOM: + //case EFFECT_MIRROR_COAT: + case EFFECT_SKULL_BASH: + case EFFECT_FOCUS_PUNCH: + case EFFECT_SUPERPOWER: + //case EFFECT_ENDEAVOR: + case EFFECT_LOW_KICK: + // AI_CBM_HighRiskForDamage + if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && typeEffectiveness < AI_EFFECTIVENESS_x2) + score -= 10; + break; + case EFFECT_COUNTER: + case EFFECT_MIRROR_COAT: + if (IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) + score--; + if (predictedMove == MOVE_NONE || GetBattleMoveSplit(predictedMove) == SPLIT_STATUS + || DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, predictedMove)) + score -= 10; + break; + + case EFFECT_ROAR: + if (CountUsablePartyMons(battlerDef) == 0) + score -= 10; + else if (AI_DATA->defAbility == ABILITY_SUCTION_CUPS) + score -= 10; + break; + case EFFECT_TOXIC_THREAD: + if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPEED)) + score--; // may still want to just poison + //fallthrough + case EFFECT_POISON: + case EFFECT_TOXIC: + if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_LIGHT_SCREEN: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_LIGHTSCREEN + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_REFLECT: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_REFLECT + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_AURORA_VEIL: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) + || !(gBattleWeather & WEATHER_HAIL_ANY)) + score -= 10; + break; + case EFFECT_OHKO: + if (!ShouldTryOHKO(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, accuracy, move)) + score -= 10; + break; + case EFFECT_MIST: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_FOCUS_ENERGY: + if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) + score -= 10; + break; + case EFFECT_CONFUSE: + case EFFECT_SWAGGER: + case EFFECT_FLATTER: + if (!AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_PARALYZE: + if (!AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_SUBSTITUTE: + if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE || AI_DATA->defAbility == ABILITY_INFILTRATOR) + score -= 8; + else if (GetHealthPercentage(battlerAtk) <= 25) + score -= 10; + else if (B_SOUND_SUBSTITUTE >= GEN_6 && TestMoveFlagsInMoveset(battlerDef, FLAG_SOUND)) + score -= 8; + break; + case EFFECT_LEECH_SEED: + if (gStatuses3[battlerDef] & STATUS3_LEECHSEED + || IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + score -= 10; + else if (AI_DATA->defAbility == ABILITY_LIQUID_OOZE) + score -= 3; + break; + case EFFECT_DISABLE: + if (gDisableStructs[battlerDef].disableTimer == 0 + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) + && !PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + { + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + { + if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) + score -= 10; // no anticipated move to disable + } + else if (predictedMove == MOVE_NONE) + { + score -= 10; + } + } + else + { + score -= 10; + } + break; + case EFFECT_ENCORE: + if (gDisableStructs[battlerDef].encoreTimer == 0 + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) + && !DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + { + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + { + if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) + score -= 10; // no anticipated move to encore + } + else if (predictedMove == MOVE_NONE) + { + score -= 10; + } + } + else + { + score -= 10; + } + break; + case EFFECT_SNORE: + case EFFECT_SLEEP_TALK: + if (IsWakeupTurn(battlerAtk) || (!(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) || AI_DATA->atkAbility != ABILITY_COMATOSE)) + score -= 10; // if mon will wake up, is not asleep, or is not comatose + break; + case EFFECT_MEAN_LOOK: + if (IsBattlerTrapped(battlerDef, TRUE) || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_NIGHTMARE: + if (gBattleMons[battlerDef].status2 & STATUS2_NIGHTMARE) + score -= 10; + else if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP) || AI_DATA->defAbility == ABILITY_COMATOSE) + score -= 8; + else if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_CURSE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) + { + if (gBattleMons[battlerDef].status2 & STATUS2_CURSED + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + score -= 10; + else if (GetHealthPercentage(battlerAtk) <= 50) + score -= 6; + } + else // regular curse + { + if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + score -= 10; + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + score -= 8; + } + break; + case EFFECT_SPIKES: + if (gSideTimers[GetBattlerSide(battlerDef)].spikesAmount >= 3) + score -= 10; + else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) + && gSideTimers[GetBattlerSide(battlerDef)].spikesAmount == 2) + 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(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) //Only one mon needs to set up Stealth Rocks + score -= 10; + break; + case EFFECT_TOXIC_SPIKES: + if (gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount >= 2) + score -= 10; + else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount == 1) + 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) + score -= 10; + else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) + score -= 10; // only one mon needs to set up Sticky Web + break; + case EFFECT_FORESIGHT: + if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT) + score -= 10; + else if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 + || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + score -= 9; + break; + case EFFECT_PERISH_SONG: + if (isDoubleBattle) + { + if (CountUsablePartyMons(battlerAtk) == 0 + && AI_DATA->atkAbility != ABILITY_SOUNDPROOF + && AI_DATA->atkPartnerAbility != ABILITY_SOUNDPROOF + && CountUsablePartyMons(FOE(battlerAtk)) >= 1) + { + score -= 10; //Don't wipe your team if you're going to lose + } + else if ((!IsBattlerAlive(FOE(battlerAtk)) || AI_GetAbility(FOE(battlerAtk)) == ABILITY_SOUNDPROOF + || gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG) + && (!IsBattlerAlive(BATTLE_PARTNER(FOE(battlerAtk))) || AI_GetAbility(BATTLE_PARTNER(FOE(battlerAtk))) == ABILITY_SOUNDPROOF + || gStatuses3[BATTLE_PARTNER(FOE(battlerAtk))] & STATUS3_PERISH_SONG)) + { + score -= 10; //Both enemies are perish songed + } + else if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + { + score -= 10; + } + } + else + { + if (CountUsablePartyMons(battlerAtk) == 0 && AI_DATA->atkAbility != ABILITY_SOUNDPROOF + && CountUsablePartyMons(battlerDef) >= 1) + score -= 10; + + if (gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG || AI_GetAbility(FOE(battlerAtk)) == ABILITY_SOUNDPROOF) + score -= 10; + } + break; + case EFFECT_SANDSTORM: + if (gBattleWeather & WEATHER_SANDSTORM_ANY //TODO | WEATHER_PRIMAL_ANY) + || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) + score -= 8; + break; + case EFFECT_SUNNY_DAY: + if (gBattleWeather & WEATHER_SUN_ANY //TODO | WEATHER_PRIMAL_ANY) + || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) + score -= 8; + break; + case EFFECT_RAIN_DANCE: + if (gBattleWeather & WEATHER_RAIN_ANY //TODO | WEATHER_PRIMAL_ANY) + || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) + score -= 8; + break; + case EFFECT_HAIL: + if (gBattleWeather & WEATHER_HAIL_ANY //TODO | WEATHER_PRIMAL_ANY) + || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) + score -= 8; + break; + case EFFECT_ATTRACT: + if (!AI_CanBeInfatuated(battlerAtk, battlerDef, AI_DATA->defAbility, + GetGenderFromSpeciesAndPersonality(gBattleMons[battlerAtk].species, gBattleMons[battlerAtk].personality), + GetGenderFromSpeciesAndPersonality(gBattleMons[battlerDef].species, gBattleMons[battlerDef].personality))) + score -= 10; + break; + case EFFECT_SAFEGUARD: + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_SAFEGUARD + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_MAGNITUDE: + if (AI_DATA->defAbility == ABILITY_LEVITATE) + score -= 10; + break; + case EFFECT_PARTING_SHOT: + if (CountUsablePartyMons(battlerAtk) == 0) + score -= 10; + break; + case EFFECT_BATON_PASS: + if (CountUsablePartyMons(battlerAtk) == 0) + 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 + score -= 6; + break; + case EFFECT_HIT_ESCAPE: + break; + case EFFECT_RAPID_SPIN: + if ((gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED) || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED)) + break; // check damage/accuracy + //Spin checks + if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY)) + score -= 6; + break; + case EFFECT_BELLY_DRUM: + if (AI_DATA->atkAbility == ABILITY_CONTRARY) + score -= 10; + else if (GetHealthPercentage(battlerAtk) <= 60) + score -= 10; + break; + case EFFECT_FUTURE_SIGHT: + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_FUTUREATTACK + || gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_FUTUREATTACK) + score -= 12; + else + score += 5; + break; + case EFFECT_TELEPORT: + score -= 10; + break; + case EFFECT_FAKE_OUT: + if (!gDisableStructs[battlerAtk].isFirstTurn) + { + score -= 10; + } + else if (move == MOVE_FAKE_OUT) // filter out first impression + { + if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || AI_DATA->atkAbility == ABILITY_GORILLA_TACTICS) + && (CountUsablePartyMons(battlerDef) > 0 || !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))) + { + if (CountUsablePartyMons(battlerAtk) == 0) + score -= 10; // Don't lock the attacker into Fake Out if they can't switch out afterwards. + } + } + break; + case EFFECT_STOCKPILE: + if (gDisableStructs[battlerAtk].stockpileCounter >= 3) + score -= 10; + break; + case EFFECT_SPIT_UP: + if (gDisableStructs[battlerAtk].stockpileCounter <= 1) + score -= 10; + break; + case EFFECT_SWALLOW: + if (gDisableStructs[battlerAtk].stockpileCounter == 0) + { + score -= 10; + } + else + { + if (AtMaxHp(battlerAtk)) + score -= 10; + else if (GetHealthPercentage(battlerAtk) >= 80) + score -= 5; // do it if nothing better + } + break; + case EFFECT_TORMENT: + if (gBattleMons[battlerDef].status2 & STATUS2_TORMENT + || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + { + score -= 10; + break; + } + + if (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect == HOLD_EFFECT_CURE_ATTRACT) + score -= 6; + break; + case EFFECT_WILL_O_WISP: + if (!AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_MEMENTO: + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + score -= 10; + else if (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE && gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE) + score -= 10; + break; + case EFFECT_FOLLOW_ME: + case EFFECT_HELPING_HAND: + if (!isDoubleBattle + || !IsBattlerAlive(AI_DATA->battlerAtkPartner) + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) + || (AI_DATA->partnerMove != MOVE_NONE && IS_MOVE_STATUS(AI_DATA->partnerMove)) + || *(gBattleStruct->monToSwitchIntoId + AI_DATA->battlerAtkPartner) != PARTY_SIZE) //Partner is switching out. + score -= 10; + break; + case EFFECT_TRICK: + case EFFECT_KNOCK_OFF: + if (AI_DATA->defAbility == ABILITY_STICKY_HOLD) + score -= 10; + break; + case EFFECT_INGRAIN: + if (gStatuses3[battlerAtk] & STATUS3_ROOTED) + score -= 10; + break; + case EFFECT_AQUA_RING: + if (gStatuses3[battlerAtk] & STATUS3_AQUA_RING) + score -= 10; + break; + case EFFECT_RECYCLE: + if (gBattleStruct->usedHeldItems[battlerAtk] == 0 || gBattleMons[battlerAtk].item != 0) + score -= 10; + break; + case EFFECT_IMPRISON: + if (gStatuses3[battlerAtk] & STATUS3_IMPRISONED_OTHERS) + score -= 10; + break; + case EFFECT_REFRESH: + if (!(gBattleMons[battlerDef].status1 & (STATUS1_PSN_ANY | STATUS1_BURN | STATUS1_PARALYSIS))) + score -= 10; + break; + case EFFECT_PSYCHO_SHIFT: + if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + score -= 10; + else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && !AI_CanBurn(battlerAtk, battlerDef, + AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 10; + else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + score -= 10; + else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + score -= 10; + else + score -= 10; // attacker has no status to transmit + break; + case EFFECT_MUD_SPORT: + if (gFieldStatuses & STATUS_FIELD_MUDSPORT + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_WATER_SPORT: + if (gFieldStatuses & STATUS_FIELD_WATERSPORT + || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 10; + break; + case EFFECT_ABSORB: + if (AI_DATA->defAbility == ABILITY_LIQUID_OOZE) + score -= 6; + break; + case EFFECT_STRENGTH_SAP: + if (AI_DATA->defAbility == ABILITY_CONTRARY) + score -= 10; + else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) + 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(AI_DATA->battlerAtkPartner, TYPE_GRASS))) + score -= 10; + break; + case EFFECT_AROMATIC_MIST: + if (!isDoubleBattle || gBattleMons[AI_DATA->battlerAtkPartner].hp == 0 || !BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPDEF)) + score -= 10; + break; case EFFECT_BIDE: if (!HasDamagingMove(battlerDef) || GetHealthPercentage(battlerAtk) < 30 //Close to death || gBattleMons[battlerDef].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) //No point in biding if can't take damage score -= 10; break; - case EFFECT_ROAR: - if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - score -= 10; // don't scare away pokemon twice - - //Don't blow out a Pokemon that'll faint soon or is taking a a lot of secondary damage - if (GetHealthPercentage(battlerDef) < 10 && GetBattlerSecondaryDamage(battlerDef)) - score -= 10; - else if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) - score -= 10; - - if (CountUsablePartyMons(battlerDef) == 0 - || AI_DATA->defAbility == ABILITY_SUCTION_CUPS - || gStatuses3[battlerDef] & STATUS3_ROOTED) - score -= 10; - break; case EFFECT_HIT_SWITCH_TARGET: if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; // don't scare away pokemon twice @@ -1148,45 +1593,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) else if (GetHealthPercentage(battlerAtk) >= 90) score -= 8; //No point in healing, but should at least do it if nothing better break; - case EFFECT_TOXIC_THREAD: - if (gBattleMons[battlerDef].statStages[STAT_SPEED] > MIN_STAT_STAGE && AI_DATA->defAbility != ABILITY_CONTRARY) - score -= 10; - //fallthrough - case EFFECT_POISON: - case EFFECT_TOXIC: - if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) - score -= 10; - else if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - score -= 10; - break; - case EFFECT_LIGHT_SCREEN: - if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_LIGHTSCREEN - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - else if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL) - score--; //can use move, but it doesn't stack with light screen - break; - case EFFECT_REFLECT: - if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_REFLECT - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - else if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL) - score--; // can use, but doesn't stack with reflect - break; - case EFFECT_AURORA_VEIL: - if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) - || !(gBattleWeather & WEATHER_HAIL_ANY)) - score -= 10; - else if (gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN)) - score--; // can use, but won't stack - break; - case EFFECT_OHKO: - if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) - score -= 10; - if (!ShouldTryOHKO(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, accuracy, move)) - score -= 10; - break; case EFFECT_SUPER_FANG: if (GetHealthPercentage(battlerDef) < 50) score -= 4; @@ -1195,15 +1601,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && accuracy < 75) score -= 6; break; - case EFFECT_MIST: - if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_FOCUS_ENERGY: - if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) - score -= 10; - break; case EFFECT_RECOIL_25: if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && AI_DATA->atkAbility != ABILITY_ROCK_HEAD) { @@ -1232,10 +1629,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; } break; - case EFFECT_CONFUSE: - if (!AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - break; case EFFECT_TEETER_DANCE: if (((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && AI_DATA->defAbility == ABILITY_OWN_TEMPO) @@ -1254,26 +1647,14 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || (gBattleMons[battlerDef].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE))) //Leave out Illusion b/c AI is supposed to be fooled score -= 10; break; - case EFFECT_PARALYZE: - if (move != MOVE_GLARE && gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - score -= 10; - else if (!AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) - score -= 10; - break; case EFFECT_TWO_TURNS_ATTACK: if (AI_DATA->atkHoldEffect != HOLD_EFFECT_POWER_HERB && CanTargetFaintAi(battlerDef, battlerAtk)) score -= 6; break; - case EFFECT_SUBSTITUTE: - if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE - || GetHealthPercentage(battlerAtk) <= 25 - || AI_DATA->defAbility == ABILITY_INFILTRATOR) - score -= 10; - else if (B_SOUND_SUBSTITUTE >= GEN_6 && TestMoveFlagsInMoveset(battlerDef, FLAG_SOUND)) - score -= 10; - break; case EFFECT_RECHARGE: - if (AI_DATA->atkAbility != ABILITY_TRUANT + if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && typeEffectiveness < AI_EFFECTIVENESS_x2) + score -= 10; + else if (AI_DATA->atkAbility != ABILITY_TRUANT && !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) score -= 2; break; @@ -1293,72 +1674,12 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_METRONOME: break; - case EFFECT_LEECH_SEED: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) - || gStatuses3[battlerDef] & STATUS3_LEECHSEED - || AI_DATA->defAbility == ABILITY_LIQUID_OOZE - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_DISABLE: - if (gDisableStructs[battlerDef].disableTimer == 0 - && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) - && !PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - { - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first - { - if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) - score -= 10; - } - else if (predictedMove == MOVE_NONE) - { - score -= 10; - } - } - else - { - score -= 10; - } - break; - case EFFECT_COUNTER: - case EFFECT_MIRROR_COAT: - if (IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) - score--; - if (predictedMove == MOVE_NONE || GetBattleMoveSplit(predictedMove) == SPLIT_STATUS - || DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, predictedMove)) - score -= 10; - break; - case EFFECT_ENCORE: - if (gDisableStructs[battlerDef].encoreTimer == 0 - && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_ATTRACT) - && !DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - { - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first - { - if (gLastMoves[battlerDef] == MOVE_NONE - || gLastMoves[battlerDef] == 0xFFFF) - score -= 10; - } - else if (predictedMove == MOVE_NONE) - { - score -= 10; - } - } - else - { - score -= 10; - } - break; case EFFECT_ENDEAVOR: case EFFECT_PAIN_SPLIT: if (gBattleMons[battlerAtk].hp > (gBattleMons[battlerAtk].hp + gBattleMons[battlerDef].hp) / 2) score -= 10; break; - case EFFECT_SNORE: - case EFFECT_SLEEP_TALK: - if (IsWakeupTurn(battlerAtk) || (!(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) && AI_DATA->atkAbility != ABILITY_COMATOSE)) - score -= 10; - break; + case EFFECT_CONVERSION_2: //TODO break; @@ -1390,36 +1711,8 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!AnyPartyMemberStatused(battlerAtk, TestMoveFlags(move, FLAG_SOUND)) || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; - case EFFECT_MEAN_LOOK: - if (IsBattlerTrapped(battlerDef, TRUE) - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - score -= 10; - break; case EFFECT_HIT_PREVENT_ESCAPE: break; - case EFFECT_NIGHTMARE: - if (gBattleMons[battlerDef].status2 & STATUS2_NIGHTMARE - || !(gBattleMons[battlerDef].status1 & STATUS1_SLEEP || AI_DATA->defAbility == ABILITY_COMATOSE) - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_CURSE: - if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) - { - if (gBattleMons[battlerDef].status2 & STATUS2_CURSED - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - score -= 10; - else if (GetHealthPercentage(battlerAtk) <= 50) - score -= 6; - } - else //Regular Curse - { - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) - && !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF) - && !BattlerStatCanFall(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) - score -= 10; - } - break; case EFFECT_ENDURE: if (gBattleMons[battlerAtk].hp == 1 || GetBattlerSecondaryDamage(battlerAtk)) //Don't use Endure if you'll die after using it score -= 10; @@ -1489,43 +1782,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) IncreaseAllyProtectionViability(&viability, 0xFF); }*/ } - break; - case EFFECT_SPIKES: - if (gSideTimers[GetBattlerSide(battlerDef)].spikesAmount >= 3) - score -= 10; - else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) - && gSideTimers[GetBattlerSide(battlerDef)].spikesAmount == 2) - 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(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) //Only one mon needs to set up Stealth Rocks - score -= 10; - break; - case EFFECT_TOXIC_SPIKES: - if (gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount >= 2) - score -= 10; - else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount == 1) - 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) - score -= 10; - else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) - score -= 10; //Only one mon needs to set up Sticky Web - break; - case EFFECT_FORESIGHT: - if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT) - { - score -= 10; - } - else if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 - || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - { - score -= 9; - } - break; + break; case EFFECT_MIRACLE_EYE: if (gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED) score -= 10; @@ -1535,102 +1792,10 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 9; break; - case EFFECT_PERISH_SONG: - if (isDoubleBattle) - { - if (CountUsablePartyMons(battlerAtk) == 0 - && AI_DATA->atkAbility != ABILITY_SOUNDPROOF - && AI_DATA->atkPartnerAbility != ABILITY_SOUNDPROOF - && CountUsablePartyMons(FOE(battlerAtk)) >= 1) - { - score -= 10; //Don't wipe your team if you're going to lose - } - else if ((!IsBattlerAlive(FOE(battlerAtk)) || AI_GetAbility(FOE(battlerAtk)) == ABILITY_SOUNDPROOF - || gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG) - && (!IsBattlerAlive(BATTLE_PARTNER(FOE(battlerAtk))) || AI_GetAbility(BATTLE_PARTNER(FOE(battlerAtk))) == ABILITY_SOUNDPROOF - || gStatuses3[BATTLE_PARTNER(FOE(battlerAtk))] & STATUS3_PERISH_SONG)) - { - score -= 10; //Both enemies are perish songed - } - else if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - score -= 10; - } - else - { - if (CountUsablePartyMons(battlerAtk) == 0 && AI_DATA->atkAbility != ABILITY_SOUNDPROOF - && CountUsablePartyMons(battlerDef) >= 1) - score -= 10; - - if (gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG || AI_GetAbility(FOE(battlerAtk)) == ABILITY_SOUNDPROOF) - score -= 10; - } - break; - case EFFECT_SANDSTORM: - if (gBattleWeather & WEATHER_SANDSTORM_ANY //TODO | WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_SUNNY_DAY: - if (gBattleWeather & WEATHER_SUN_ANY //TODO | WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_RAIN_DANCE: - if (gBattleWeather & WEATHER_RAIN_ANY //TODO | WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_HAIL: - if (gBattleWeather & WEATHER_HAIL_ANY //TODO | WEATHER_PRIMAL_ANY | WEATHER_CIRCUS) - || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_SWAGGER: - if (AI_DATA->targetSameSide && AI_DATA->defAbility == ABILITY_CONTRARY) - score -= 10; - else if (!AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_ATTRACT: - { - u8 atkGender = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerAtk].species, gBattleMons[battlerAtk].personality); - u8 defGender = GetGenderFromSpeciesAndPersonality(gBattleMons[battlerDef].species, gBattleMons[battlerDef].personality); - if (!AI_CanBeInfatuated(battlerAtk, battlerDef, AI_DATA->defAbility, atkGender, defGender) - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - score -= 10; - } - break; - case EFFECT_SAFEGUARD: - if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_SAFEGUARD - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - break; case EFFECT_BURN_UP: if (!IS_BATTLER_OF_TYPE(battlerAtk, TYPE_FIRE)) score -= 10; break; - case EFFECT_PARTING_SHOT: - if (CountUsablePartyMons(battlerAtk) == 0) - score -= 10; - break; - case EFFECT_BATON_PASS: - if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE - || (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING | STATUS3_MAGNET_RISE | STATUS3_POWER_TRICK)) - || AnyStatIsRaised(battlerAtk)) - break; - - score -= 6; - break; - case EFFECT_HIT_ESCAPE: - break; - case EFFECT_RAPID_SPIN: - if ((gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED) || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED)) - break; // check damage/accuracy - - //Spin checks - if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY)) - score -= 6; - break; case EFFECT_DEFOG: if (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST) @@ -1662,15 +1827,10 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // evasion check if (gBattleMons[battlerDef].statStages[STAT_EVASION] == MIN_STAT_STAGE - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide)) // don't want to raise target stats unless its your partner - score -= 10; - break; - case EFFECT_BELLY_DRUM: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) - score -= 10; - else if (GetHealthPercentage(battlerAtk) <= 60) + || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !IsTargetingPartner(battlerAtk, battlerDef))) // don't want to raise target stats unless its your partner score -= 10; break; + case EFFECT_PSYCH_UP: // haze stats check { for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) @@ -1687,10 +1847,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SPECTRAL_THIEF: break; - case EFFECT_FUTURE_SIGHT: - if (gWishFutureKnock.futureSightCounter[battlerDef] != 0) - score -= 10; - break; case EFFECT_SOLARBEAM: if (AI_DATA->atkHoldEffect == HOLD_EFFECT_POWER_HERB || (AI_WeatherHasEffect() && gBattleWeather & WEATHER_SUN_ANY && AI_DATA->atkHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA)) @@ -1708,72 +1864,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && (move == MOVE_FLY || move == MOVE_BOUNCE)) score -= 10; // Attacker will faint while in the air break; - case EFFECT_FAKE_OUT: - // first impression check - if (!gDisableStructs[battlerAtk].isFirstTurn) - { - score -= 10; - } - else if (move == MOVE_FAKE_OUT) - { - if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || AI_DATA->atkAbility == ABILITY_GORILLA_TACTICS) - && (CountUsablePartyMons(battlerDef) > 0 || !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))) - { - if (CountUsablePartyMons(battlerAtk) == 0) - score -= 10; // Don't lock the attacker into Fake Out if they can't switch out afterwards. - } - } - break; //damage checks - case EFFECT_STOCKPILE: - if (gDisableStructs[battlerAtk].stockpileCounter >= 3) - score -= 10; - break; - case EFFECT_SPIT_UP: - if (gDisableStructs[battlerAtk].stockpileCounter == 1) - score -= 10; - else if (gDisableStructs[battlerAtk].stockpileCounter <= 1) - score -= 2; - break; - case EFFECT_SWALLOW: - if (gDisableStructs[battlerAtk].stockpileCounter == 0) - { - score -= 10; - } - else - { - if (AtMaxHp(battlerAtk)) - score -= 10; - else if (GetHealthPercentage(battlerAtk) >= 80) - score -= 5; // do it if nothing better - } - break; - case EFFECT_TORMENT: - if (gBattleMons[battlerDef].status2 & STATUS2_TORMENT - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - { - score -= 10; - break; - } - - if (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect == HOLD_EFFECT_CURE_ATTRACT) - score -= 6; - break; - case EFFECT_FLATTER: - if (AI_DATA->targetSameSide && AI_DATA->defAbility == ABILITY_CONTRARY) - score -= 10; - else if (!AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_WILL_O_WISP: - if (!AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_MEMENTO: - if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) - score -= 10; - else if (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE && gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE) - score -= 10; - break; case EFFECT_HEALING_WISH: //healing wish, lunar dance if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; @@ -1784,50 +1874,13 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; - case EFFECT_FOCUS_PUNCH: - if (predictedMove != MOVE_NONE - && !DoesSubstituteBlockMove(battlerAtk, battlerDef, move) - && !IS_MOVE_STATUS(predictedMove) - && gBattleMoves[predictedMove].power != 0) - score -= 10; // Probably better not to use it - break; case EFFECT_NATURE_POWER: return AI_CheckBadMove(battlerAtk, battlerDef, GetNaturePowerMove(), score); - case EFFECT_CHARGE: - if (gStatuses3[battlerAtk] & STATUS3_CHARGED_UP) - { - score -= 10; - break; - } - else if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC)) - { - if (AI_DATA->atkAbility == ABILITY_CONTRARY || !BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) - score -= 10; - } - break; case EFFECT_TAUNT: if (gDisableStructs[battlerDef].tauntTimer > 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score--; break; - case EFFECT_FOLLOW_ME: - case EFFECT_HELPING_HAND: - if (!isDoubleBattle - || !IsBattlerAlive(AI_DATA->battlerAtkPartner) - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) - || (AI_DATA->partnerMove != MOVE_NONE && IS_MOVE_STATUS(AI_DATA->partnerMove)) - || *(gBattleStruct->monToSwitchIntoId + AI_DATA->battlerAtkPartner) != PARTY_SIZE) //Partner is switching out. - score -= 10; - break; - case EFFECT_TRICK: - if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_NONE && AI_DATA->defHoldEffect == HOLD_EFFECT_NONE) - || AI_DATA->defAbility == ABILITY_STICKY_HOLD - || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item) - || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerDef].item) - || !CanBattlerGetOrLoseItem(battlerDef, gBattleMons[battlerAtk].item) - || !CanBattlerGetOrLoseItem(battlerDef, gBattleMons[battlerDef].item)) - score -= 10; // kinda cheating with battlerDef item check, but only item effects recorded - break; case EFFECT_BESTOW: if (AI_DATA->atkHoldEffect == HOLD_EFFECT_NONE || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item)) // AI knows its own item @@ -1850,30 +1903,10 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (CountUsablePartyMons(battlerAtk) == 0) score -= 10; // no teammates to assist from break; - case EFFECT_INGRAIN: - if (gStatuses3[battlerAtk] & STATUS3_ROOTED) - score -= 10; - break; - case EFFECT_AQUA_RING: - if (gStatuses3[battlerAtk] & STATUS3_AQUA_RING) - score -= 10; - break; - case EFFECT_SUPERPOWER: - #ifdef POKEMON_EXPANSION - if (move == MOVE_HYPERSPACE_FURY && gBattleMons[battlerAtk].species != SPECIES_HOOPA_UNBOUND) - score -= 10; - #endif - if (effectiveness <= AI_EFFECTIVENESS_x0_5) - score -= 2; // really don't waste the stat loss on a weak attack - break; case EFFECT_MAGIC_COAT: if (!TestMoveFlagsInMoveset(battlerDef, FLAG_MAGICCOAT_AFFECTED)) score -= 10; break; - case EFFECT_RECYCLE: - if (gBattleStruct->usedHeldItems[battlerAtk] == 0 || gBattleMons[battlerAtk].item != 0) - score -= 10; - break; case EFFECT_BELCH: if (ItemId_GetPocket(gBattleStruct->usedHeldItems[battlerAtk]) != POCKET_BERRIES) score -= 10; // attacker has not consumed a berry @@ -1884,17 +1917,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) else if (!AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) score -= 10; break; - case EFFECT_KNOCK_OFF: - /*if (AI_DATA->defHoldEffect == HOLD_EFFECT_ASSAULT_VEST - || (AI_DATA->defHoldEffect == HOLD_EFFECT_CHOICE_BAND && AI_DATA->atkAbility != ABILITY_GORILLA_TACTICS && gBattleStruct->choicedMove[battlerDef])) - { - if (GetStrongestMove(battlerDef, battlerAtk) == MOVE_NONE - || AI_SpecialTypeCalc(GetStrongestMove(battlerDef, battlerAtk), battlerDef, battlerAtk) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) - DECREASE_VIABILITY(9); //Don't use Knock Off is the enemy's only moves don't affect the AI - }*/ - if (AI_DATA->defHoldEffect == HOLD_EFFECT_NONE) - score -= 4; - break; case EFFECT_SKILL_SWAP: if (AI_DATA->atkAbility == ABILITY_NONE || AI_DATA->defAbility == ABILITY_NONE || IsSkillSwapBannedAbility(AI_DATA->atkAbility) || IsSkillSwapBannedAbility(AI_DATA->defAbility)) @@ -1923,132 +1945,33 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || IsEntrainmentTargetOrSimpleBeamBannedAbility(AI_DATA->defAbility)) score -= 10; break; - case EFFECT_IMPRISON: - if (gStatuses3[battlerAtk] & STATUS3_IMPRISONED_OTHERS) - score -= 10; - break; - case EFFECT_REFRESH: - if (!(gBattleMons[battlerDef].status1 & (STATUS1_PSN_ANY | STATUS1_BURN | STATUS1_PARALYSIS))) - score -= 10; - break; - case EFFECT_PSYCHO_SHIFT: - if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) - score -= 10; - else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && !AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) - score -= 10; - else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) - score -= 10; - else - score -= 10; - break; case EFFECT_SNATCH: if (!TestMoveFlagsInMoveset(battlerDef, FLAG_SNATCH_AFFECTED) || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) score -= 10; break; - case EFFECT_MUD_SPORT: - if (gFieldStatuses & STATUS_FIELD_MUDSPORT - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_WATER_SPORT: - if (gFieldStatuses & STATUS_FIELD_WATERSPORT - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) - score -= 10; - break; - case EFFECT_TICKLE: - if ((AI_DATA->defAbility == ABILITY_CONTRARY) && !AI_DATA->targetSameSide) - score -= 10; - else if ((gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE || !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) - && gBattleMons[battlerDef].statStages[STAT_DEF] == MIN_STAT_STAGE) - score -= 10; - break; - case EFFECT_COSMIC_POWER: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) - score -= 10; - else if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE - && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) - score -= 10; - break; - case EFFECT_BULK_UP: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) - score -= 10; - else if ((gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) - && gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE) - score -= 10; - break; - case EFFECT_COIL: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) - score -= 10; - else if (gBattleMons[battlerAtk].statStages[STAT_ACC] >= MAX_STAT_STAGE - && (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) - && gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE) - score -= 10; - break; - case EFFECT_CALM_MIND: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) - score -= 10; - else if ((gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) - && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) - score -= 10; - break; - case EFFECT_QUIVER_DANCE: - case EFFECT_GEOMANCY: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) - score -= 10; - else if (gBattleMons[battlerAtk].statStages[STAT_SPEED] >= MAX_STAT_STAGE - && (gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) - && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) - score -= 10; - break; - case EFFECT_DRAGON_DANCE: - case EFFECT_SHIFT_GEAR: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) - score -= 10; - else if ((gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) - && (gBattleMons[battlerAtk].statStages[STAT_SPEED] >= MAX_STAT_STAGE)) - score -= 10; - break; - case EFFECT_SHELL_SMASH: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) - { - if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= MAX_STAT_STAGE - && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= MAX_STAT_STAGE) - score -= 10; - } - else - { - if ((gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) - && (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) - && (gBattleMons[battlerAtk].statStages[STAT_SPEED] >= MAX_STAT_STAGE)) - score -= 10; - } - break; - case EFFECT_POWER_TRICK: - if (AI_DATA->targetSameSide) + if (IsTargetingPartner(battlerAtk, battlerDef)) score -= 10; else if (gBattleMons[battlerAtk].defense >= gBattleMons[battlerAtk].attack && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; break; case EFFECT_POWER_SWAP: // Don't use if attacker's stat stages are higher than opponents - if (AI_DATA->targetSameSide) + if (IsTargetingPartner(battlerAtk, battlerDef)) score -= 10; else if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= gBattleMons[battlerDef].statStages[STAT_ATK] && gBattleMons[battlerAtk].statStages[STAT_SPATK] >= gBattleMons[battlerDef].statStages[STAT_SPATK]) score -= 10; break; case EFFECT_GUARD_SWAP: // Don't use if attacker's stat stages are higher than opponents - if (AI_DATA->targetSameSide) + if (IsTargetingPartner(battlerAtk, battlerDef)) score -= 10; else if (gBattleMons[battlerAtk].statStages[STAT_DEF] >= gBattleMons[battlerDef].statStages[STAT_DEF] && gBattleMons[battlerAtk].statStages[STAT_SPDEF] >= gBattleMons[battlerDef].statStages[STAT_SPDEF]) score -= 10; break; case EFFECT_SPEED_SWAP: - if (AI_DATA->targetSameSide) + if (IsTargetingPartner(battlerAtk, battlerDef)) { score -= 10; } @@ -2061,7 +1984,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_HEART_SWAP: - if (AI_DATA->targetSameSide) + if (IsTargetingPartner(battlerAtk, battlerDef)) { score -= 10; } @@ -2078,7 +2001,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_POWER_SPLIT: - if (AI_DATA->targetSameSide) + if (IsTargetingPartner(battlerAtk, battlerDef)) { score -= 10; } @@ -2095,7 +2018,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_GUARD_SPLIT: - if (AI_DATA->targetSameSide) + if (IsTargetingPartner(battlerAtk, battlerDef)) { score -= 10; } @@ -2278,7 +2201,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_HIT_ENEMY_HEAL_ALLY: // pollen puff - if (AI_DATA->targetSameSide) + if (IsTargetingPartner(battlerAtk, battlerDef)) { if (AtMaxHp(battlerDef)) score -= 10; @@ -2288,7 +2211,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // fallthrough case EFFECT_HEAL_PULSE: // and floral healing - if (!AI_DATA->targetSameSide) // Don't heal enemies + if (!IsTargetingPartner(battlerAtk, battlerDef)) // Don't heal enemies { score -= 10; } @@ -2307,7 +2230,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_TOPSY_TURVY: - if (!AI_DATA->targetSameSide) + if (!IsTargetingPartner(battlerAtk, battlerDef)) { u8 targetPositiveStages = CountPositiveStatStages(battlerDef); u8 targetNegativeStages = CountNegativeStatStages(battlerDef); @@ -2350,7 +2273,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (isDoubleBattle) { - if (!AI_DATA->targetSameSide) + if (!IsTargetingPartner(battlerAtk, battlerDef)) score -= 10; } else @@ -2375,7 +2298,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_AFTER_YOU: - if (!AI_DATA->targetSameSide + if (!IsTargetingPartner(battlerAtk, battlerDef) || !isDoubleBattle || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) @@ -2541,6 +2464,7 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } +// double battle logic static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // move data @@ -2557,9 +2481,6 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!IsBattlerAlive(battlerAtkPartner)) return score; - - if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_HELP_PARTNER) - score += 2; // partner ability checks if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) @@ -2567,40 +2488,46 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) switch (atkPartnerAbility) { case ABILITY_VOLT_ABSORB: + if (!(AI_THINKING_STRUCT->aiFlags & 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)) - score++; + RETURN_SCORE_PLUS(1); break; case ABILITY_LIGHTNING_ROD: if (moveType == TYPE_ELECTRIC && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) - score++; + RETURN_SCORE_PLUS(1); break; case ABILITY_WATER_ABSORB: case ABILITY_DRY_SKIN: + if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HP_AWARE)) + RETURN_SCORE_MINUS(10); break; // handled in AI_HPAware case ABILITY_STORM_DRAIN: if (moveType == TYPE_WATER && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) - score++; + RETURN_SCORE_PLUS(1); break; case ABILITY_WATER_COMPACTION: - score -= 10; + if (moveType == TYPE_WATER && GetMoveDamageResult(move) == MOVE_POWER_WEAK) + RETURN_SCORE_PLUS(1); // 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)) - score++; + RETURN_SCORE_PLUS(1); break; case ABILITY_SAP_SIPPER: if (moveType == TYPE_GRASS && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) - score++; + RETURN_SCORE_PLUS(1); break; case ABILITY_JUSTIFIED: if (moveType == TYPE_DARK @@ -2608,28 +2535,28 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) - score++; + RETURN_SCORE_PLUS(1); break; case ABILITY_RATTLED: if (!IS_MOVE_STATUS(move) && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED) && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) - score++; + RETURN_SCORE_PLUS(1); break; case ABILITY_CONTRARY: if (IsStatLoweringEffect(effect)) - score += 2; + RETURN_SCORE_PLUS(2); break; case ABILITY_DEFIANT: if (IsStatLoweringEffect(effect) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) - score++; + RETURN_SCORE_PLUS(1); break; case ABILITY_COMPETITIVE: if (IsStatLoweringEffect(effect) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) - score++; + RETURN_SCORE_PLUS(1); break; } } // ability checks @@ -2643,7 +2570,7 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!IsBattlerTrapped(battlerDef, TRUE) && (gBattleMoves[move].effect == EFFECT_MEAN_LOOK || gBattleMoves[move].effect == EFFECT_TRAP)) - score++; // target not trapped, but ally will trap them so perish song is good + RETURN_SCORE_PLUS(1); // target not trapped, but ally will trap them so perish song is good break; case EFFECT_ALWAYS_CRIT: if (AI_DATA->atkAbility == ABILITY_ANGER_POINT // ai has anger point @@ -2654,7 +2581,7 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!IsAttackBoostMoveEffect(gBattleMoves[move].effect) && !IS_MOVE_STATUS(move) && gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) - score += 3; + RETURN_SCORE_PLUS(3); } break; } // partner move effects @@ -2665,11 +2592,11 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { case EFFECT_EVASION_UP: if (move == MOVE_ACUPRESSURE && !partnerProtecting) - score++; + RETURN_SCORE_PLUS(1); break; case EFFECT_PURIFY: if (gBattleMons[battlerAtkPartner].status1 & STATUS1_ANY) - score++; + RETURN_SCORE_PLUS(1); break; case EFFECT_SWAGGER: if (gBattleMons[battlerAtkPartner].statStages[STAT_ATK] < MAX_STAT_STAGE @@ -2677,7 +2604,7 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && (!CanBeConfused(battlerAtkPartner, TRUE) || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) - score++; + RETURN_SCORE_PLUS(1); break; case EFFECT_FLATTER: if (gBattleMons[battlerAtkPartner].statStages[STAT_SPATK] < MAX_STAT_STAGE @@ -2685,24 +2612,24 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && (!CanBeConfused(battlerAtkPartner, TRUE) || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) - score++; + RETURN_SCORE_PLUS(1); break; case EFFECT_SANDSTORM: if (ShouldSetSandstorm(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) - score ++; + RETURN_SCORE_PLUS(1); break; case EFFECT_RAIN_DANCE: if (ShouldSetRain(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) - score ++; + RETURN_SCORE_PLUS(1); break; case EFFECT_SUNNY_DAY: if (ShouldSetSun(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) - score ++; + RETURN_SCORE_PLUS(1); break; case EFFECT_HAIL: if (IsBattlerAlive(battlerAtkPartner) && ShouldSetHail(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) - score += 2; + RETURN_SCORE_PLUS(2); break; case EFFECT_BEAT_UP: if (atkPartnerAbility == ABILITY_JUSTIFIED @@ -2711,52 +2638,56 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) - score++; + RETURN_SCORE_PLUS(1); break; case EFFECT_HELPING_HAND: if (AI_DATA->partnerMove != MOVE_NONE && !partnerProtecting && !IS_MOVE_STATUS(AI_DATA->partnerMove)) - score++; + RETURN_SCORE_PLUS(1); break; case EFFECT_SKILL_SWAP: if (!partnerProtecting && AI_DATA->atkAbility != AI_DATA->atkPartnerAbility && !attackerHasBadAbility) { if (AI_DATA->atkPartnerAbility == ABILITY_TRUANT) - score += 10; + { + RETURN_SCORE_PLUS(10); + } else if (AI_DATA->atkAbility == ABILITY_COMPOUND_EYES && HasMoveWithLowAccuracy(battlerAtkPartner, FOE(battlerAtkPartner), 90, TRUE, atkPartnerAbility, AI_GetAbility(FOE(battlerAtkPartner)), atkPartnerHoldEffect, AI_GetHoldEffect(FOE(battlerAtkPartner)))) - score += 3; - else - score -= 30; + { + RETURN_SCORE_PLUS(3); + } + //else + //score -= 30; // we get there after breaking out } break; case EFFECT_ROLE_PLAY: if (!partnerProtecting && attackerHasBadAbility && !partnerHasBadAbility) - score++; + RETURN_SCORE_PLUS(1); break; case EFFECT_WORRY_SEED: case EFFECT_GASTRO_ACID: case EFFECT_SIMPLE_BEAM: if (!partnerProtecting && partnerHasBadAbility) - score += 2; + RETURN_SCORE_PLUS(2); break; case EFFECT_ENTRAINMENT: if (!partnerProtecting && partnerHasBadAbility && IsAbilityOfRating(AI_DATA->atkAbility, 0)) - score++; + RETURN_SCORE_PLUS(1); break; case EFFECT_SOAK: if (!partnerProtecting && atkPartnerAbility == ABILITY_WONDER_GUARD && (gBattleMons[battlerAtkPartner].type1 != TYPE_WATER || gBattleMons[battlerAtkPartner].type2 != TYPE_WATER || gBattleMons[battlerAtkPartner].type3 != TYPE_WATER)) - score++; + RETURN_SCORE_PLUS(1); break; case EFFECT_MAGNET_RISE: if (IsBattlerGrounded(battlerAtk) && (HasMove(battlerAtkPartner, MOVE_EARTHQUAKE) || HasMove(battlerAtkPartner, MOVE_MAGNITUDE)) && (AI_GetMoveEffectiveness(MOVE_EARTHQUAKE) != AI_EFFECTIVENESS_x0)) // Doesn't resist ground move - score += 2; + RETURN_SCORE_PLUS(2); break; case EFFECT_INSTRUCT: if (!partnerProtecting) @@ -2771,9 +2702,10 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && !IS_MOVE_STATUS(instructedMove) && gBattleMoves[instructedMove].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) //Use instruct on multi-target moves { - score++; + RETURN_SCORE_PLUS(1); } } + break; case EFFECT_AFTER_YOU: if (GetWhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), TRUE) == 1 // opponent mon 1 goes before partner || GetWhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), TRUE) == 1) // opponent mon 2 goes before partner @@ -2781,12 +2713,12 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_COUNTER || gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_MIRROR_COAT) break; // These moves need to go last - score++; + RETURN_SCORE_PLUS(1); } break; } // attacker move effects - - return score; + + RETURN_SCORE_MINUS(30); // otherwise, we do not want to target our ally } // AI_FLAG_CHECK_GOOD_MOVE - increases move scores @@ -2801,17 +2733,17 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u32 i; // Targeting partner, check benefits of doing that instead - if (isDoubleBattle && AI_DATA->targetSameSide) - score = AI_TryOnAlly(battlerAtk, AI_DATA->battlerAtkPartner, move, score); + if (IsTargetingPartner(battlerAtk, battlerDef)) + return score; // check move results if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) - return 0; + return 0; // don't use ineffective moves // if target goes first and can kill us, lets try to use a priority move to at least do something - if ((gBattleMons[battlerDef].status2 & (STATUS2_RECHARGE | STATUS2_BIDE)) + if (!(gBattleMons[battlerDef].status2 & (STATUS2_RECHARGE | STATUS2_BIDE)) && CanTargetFaintAi(battlerAtk, battlerDef) - && IsAiFaster(AI_CHECK_SLOWER) + && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 // opponent should go first && atkPriority > 0) score += 5; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 510da52b91..f7c846c0b8 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -859,23 +859,36 @@ u8 GetMoveDamageResult(u16 move) u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) { - u16 typeEffectiveness, moveType; + u8 damageVar; + u32 effectivenessMultiplier; - SaveBattlerData(battlerAtk); - SaveBattlerData(battlerDef); + gMoveResultFlags = 0; + gCurrentMove = AI_THINKING_STRUCT->moveConsidered; + effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, sBattler_AI, gBattlerTarget); + switch (effectivenessMultiplier) + { + case UQ_4_12(0.0): + default: + damageVar = AI_EFFECTIVENESS_x0; + break; + case UQ_4_12(0.25): + damageVar = AI_EFFECTIVENESS_x0_25; + break; + case UQ_4_12(0.5): + damageVar = AI_EFFECTIVENESS_x0_5; + break; + case UQ_4_12(1.0): + damageVar = AI_EFFECTIVENESS_x1; + break; + case UQ_4_12(2.0): + damageVar = AI_EFFECTIVENESS_x2; + break; + case UQ_4_12(4.0): + damageVar = AI_EFFECTIVENESS_x4; + break; + } - SetBattlerData(battlerAtk); - SetBattlerData(battlerDef); - - gBattleStruct->dynamicMoveType = 0; - SetTypeBeforeUsingMove(move, battlerAtk); - GET_MOVE_TYPE(move, moveType); - typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, FALSE); - - RestoreBattlerData(battlerAtk); - RestoreBattlerData(battlerDef); - - return typeEffectiveness; + return damageVar; } u8 AI_GetMoveEffectiveness(u16 move) @@ -1096,7 +1109,7 @@ bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move) u32 i; if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) - return FALSE; // AI doesn't understand ability suppression concept + return FALSE; // AI handicap flag: doesn't understand ability suppression concept for (i = 0; i < ARRAY_COUNT(sIgnoreMoldBreakerMoves); i++) { @@ -1331,7 +1344,7 @@ bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move) { u32 holdEffect = AI_GetHoldEffect(battlerDef); - + gPotentialItemEffectBattler = battlerDef; if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < GetBattlerHoldEffectParam(battlerDef)) return FALSE; //probabilistically speaking, focus band should activate so dont OHKO @@ -1499,11 +1512,19 @@ void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s1 } // stat stages -bool32 BattlerStatCanFall(u8 battler, u16 battlerAbility, u8 stat) +bool32 ShouldLowerStat(u8 battler, u16 battlerAbility, u8 stat) { if ((gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) || (battlerAbility == ABILITY_CONTRARY && gBattleMons[battler].statStages[stat] < MAX_STAT_STAGE)) + { + if (battlerAbility == ABILITY_CLEAR_BODY + || battlerAbility == ABILITY_WHITE_SMOKE + || battlerAbility == ABILITY_FULL_METAL_BODY) + return FALSE; + return TRUE; + } + return FALSE; } @@ -1562,18 +1583,6 @@ u32 CountNegativeStatStages(u8 battlerId) return count; } -// checks for growth, gear up, work up -bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability) -{ - if (((!BattlerStatCanRise(battlerId, ability, STAT_ATK)|| !HasMoveWithSplit(battlerId, SPLIT_PHYSICAL)) - && (!BattlerStatCanRise(battlerId, ability, STAT_SPATK) || !HasMoveWithSplit(battlerId, SPLIT_SPECIAL))) - || ability == ABILITY_CONTRARY) - { - return FALSE; - } - return TRUE; -} - bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) { if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) @@ -2521,7 +2530,7 @@ bool32 ShouldPoisonSelf(u8 battler, u16 ability) || (ability == ABILITY_GUTS && HasMoveWithSplit(battler, SPLIT_PHYSICAL)) || HasMoveEffect(battler, EFFECT_FACADE) || HasMoveEffect(battler, EFFECT_PSYCHO_SHIFT))) - return TRUE; + return TRUE; // battler can be poisoned and has move/ability that synergizes with being poisoned return FALSE; } @@ -2539,12 +2548,19 @@ bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 return TRUE; } -bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +static bool32 CanBeParayzed(battlerDef, defAbility) { if (defAbility == ABILITY_LIMBER || IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC) || gBattleMons[battlerDef].status1 & STATUS1_ANY - || IsAbilityStatusProtected(battlerDef) + || IsAbilityStatusProtected(battlerDef)) + return FALSE; + return TRUE; +} + +bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +{ + if (!CanBeParayzed(battlerDef, defAbility) || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) @@ -2563,7 +2579,7 @@ bool32 CanBeConfused(u8 battler, u16 ability) bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) { - if (CanBeConfused(battlerDef, defAbility) + if (!CanBeConfused(battlerDef, defAbility) || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || DoesPartnerHaveSameMoveEffect(battlerAtkPartner, battlerDef, move, partnerMove)) @@ -2613,13 +2629,12 @@ bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPar bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGender, u8 defGender) { - if (IsBattlerAlive(battlerDef) - && !(gBattleMons[battlerDef].status2 & STATUS2_INFATUATION) - && defAbility != ABILITY_OBLIVIOUS - && atkGender != defGender - && atkGender != MON_GENDERLESS - && defGender != MON_GENDERLESS - && !IsAbilityOnSide(battlerDef, ABILITY_AROMA_VEIL)) + if ((gBattleMons[battlerDef].status2 & STATUS2_INFATUATION) + || defAbility == ABILITY_OBLIVIOUS + || atkGender == defGender + || atkGender == MON_GENDERLESS + || defGender == MON_GENDERLESS + || !IsAbilityOnSide(battlerDef, ABILITY_AROMA_VEIL)) return FALSE; return TRUE; } @@ -2628,7 +2643,7 @@ u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbili { if (defAbility == ABILITY_INNER_FOCUS || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) - || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) + || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // opponent goes first { return 0; // don't try to flinch } @@ -2863,7 +2878,7 @@ bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef) if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) return FALSE; - if (battlerDef == BATTLE_PARTNER(battlerAtk)) + if ((battlerAtk & BIT_SIDE) == (battlerDef & BIT_SIDE)) return TRUE; return FALSE; From f21b0140b9abeeebe76121397e2123e9ddf1402f Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 4 Jan 2021 19:39:59 -0700 Subject: [PATCH 16/36] revert to CheckViability and stat change effect viabilities --- include/battle_ai_util.h | 16 +- include/constants/battle_ai.h | 2 +- src/battle_ai_main.c | 450 ++++++++++++++++++++++------------ src/battle_ai_util.c | 57 +++-- src/battle_factory.c | 4 +- src/data/trainers.h | 358 +++++++++++++-------------- src/trainer_hill.c | 2 +- 7 files changed, 523 insertions(+), 366 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 6ecebc03ec..2aae8a61a6 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -7,6 +7,7 @@ #define FOE(battler) ((battler ^ BIT_SIDE) & BIT_SIDE) +bool32 AI_RandLessThan(u8 val); void RecordLastUsedMoveByTarget(void); bool32 IsBattlerAIControlled(u32 battlerId); void ClearBattlerMoveHistory(u8 battlerId); @@ -61,19 +62,20 @@ bool32 AreBattlersStatsMaxed(u8 battler); bool32 BattlerHasAnyStatRaised(u8 battlerId); u32 CountPositiveStatStages(u8 battlerId); u32 CountNegativeStatStages(u8 battlerId); -bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); -bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); -bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); -bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); -bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); -bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); -bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex); +bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility); +bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility); +bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility); +bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility); +bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility); +bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility); +bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility); // move checks bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect); bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split); s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef); u8 GetMoveDamageResult(u16 move); +u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef); u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); u8 AI_GetMoveEffectiveness(u16 move); u16 *GetMovesArray(u32 battler); diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 43a21fa0f2..6b17a53795 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -38,7 +38,7 @@ // 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_GOOD_MOVE (1 << 2) // was AI_SCRIPT_CHECK_VIABILITY +#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) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index dce550fcf8..8ccb05640f 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -48,7 +48,7 @@ EWRAM_DATA u8 sBattler_AI = 0; // const rom data static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); @@ -63,7 +63,7 @@ static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = { [0] = AI_CheckBadMove, // AI_FLAG_CHECK_BAD_MOVE [1] = AI_TryToFaint, // AI_FLAG_TRY_TO_FAINT - [2] = AI_CheckGoodMove, // AI_FLAG_CHECK_GOOD_MOVE + [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 @@ -136,7 +136,7 @@ void BattleAI_SetupFlags(void) else if (gBattleTypeFlags & BATTLE_TYPE_FACTORY) AI_THINKING_STRUCT->aiFlags = GetAiScriptsInBattleFactory(); else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE)) - AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_TRY_TO_FAINT; + AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT; else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags | gTrainers[gTrainerBattleOpponent_B].aiFlags; else @@ -278,13 +278,13 @@ static u8 ChooseMoveOrAction_Singles(void) && !(gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) && !(gStatuses3[gActiveBattler] & STATUS3_ROOTED) && !(gBattleTypeFlags & (BATTLE_TYPE_ARENA | BATTLE_TYPE_PALACE)) - && AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_PREFER_BATON_PASS)) + && AI_THINKING_STRUCT->aiFlags & (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[sBattler_AI].species) >= 310 // Mon is not weak. && gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2) { - s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_GOOD_MOVE) ? 95 : 93; + s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY) ? 95 : 93; for (i = 0; i < MAX_MON_MOVES; i++) { if (AI_THINKING_STRUCT->score[i] > cap) @@ -2094,7 +2094,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (GetBattlerSideSpeedAverage(battlerAtk) > GetBattlerSideSpeedAverage(battlerDef)) // Attacker side faster than target side + if (GetBattlerSideSpeedAverage(battlerAtk) >= GetBattlerSideSpeedAverage(battlerDef)) // Attacker side faster than target side score -= 10; // Keep the Trick Room down } break; @@ -2393,27 +2393,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break;*/ } // move effect checks - // substitute check - if (IS_MOVE_STATUS(move) && DoesSubstituteBlockMove(battlerAtk, battlerDef, move)) - score -= 10; - - // damage check - if (!IS_MOVE_STATUS(move)) - { - if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) - score -= 15; - - if (effectiveness < AI_EFFECTIVENESS_x1 || GetMoveDamageResult(move) <= MOVE_POWER_WEAK) - score -= 4; - } - - // helping hand check - if (isDoubleBattle - && AI_DATA->partnerMove != MOVE_NONE - && gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_HELPING_HAND - && IS_MOVE_STATUS(move)) - score -= 10; // Don't use a status move if partner helping - if (score < 0) score = 0; @@ -2721,53 +2700,68 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) RETURN_SCORE_MINUS(30); // otherwise, we do not want to target our ally } -// AI_FLAG_CHECK_GOOD_MOVE - increases move scores -static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +// AI_FLAG_CHECK_VIABILITY - a weird mix of increasing and decreasing scores +static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // move data u16 moveEffect = gBattleMoves[move].effect; u8 effectiveness = AI_GetMoveEffectiveness(move); + u8 typeEffectiveness = AI_GetTypeEffectiveness(move, battlerAtk, battlerDef); u8 atkPriority = GetMovePriority(battlerAtk, move); u16 predictedMove = gLastMoves[battlerDef]; //for now bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); u32 i; + u8 atkHpPercent = GetHealthPercentage(battlerAtk); + u8 defHpPercent = GetHealthPercentage(battlerDef); // Targeting partner, check benefits of doing that instead if (IsTargetingPartner(battlerAtk, battlerDef)) return score; - // check move results - if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) - return 0; // don't use ineffective moves - - // if target goes first and can kill us, lets try to use a priority move to at least do something - if (!(gBattleMons[battlerDef].status2 & (STATUS2_RECHARGE | STATUS2_BIDE)) - && CanTargetFaintAi(battlerAtk, battlerDef) - && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 // opponent should go first - && atkPriority > 0) - score += 5; - - // if target is evasive (or we have low accuracy)) and this move always hits, boost its score + // check always hits if (!IS_MOVE_STATUS(move) && gBattleMoves[move].accuracy == 0) { - if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 8) + if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 10 || gBattleMons[battlerAtk].statStages[STAT_ACC] <= 2) score++; - else if (gBattleMons[battlerAtk].statStages[STAT_ACC] <= 4) + if (AI_RandLessThan(100) && (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 8 || gBattleMons[battlerAtk].statStages[STAT_ACC] <= 4)) score++; } - // prefer good damaging moves - if (GetMoveDamageResult(move) == MOVE_POWER_BEST) - score += 2; + // check high crit + if (TestMoveFlags(move, FLAG_HIGH_CRIT) && effectiveness >= AI_EFFECTIVENESS_x2 && AI_RandLessThan(128)) + score++; + + // check already dead + if (!IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) + && CanTargetFaintAi(battlerAtk, battlerDef) + && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // opponent should go first + { + if (atkPriority > 0) + score++; + else + score--; + } + + // check damage + if (gBattleMoves[move].power != 0 && GetMoveDamageResult(move) == MOVE_POWER_WEAK) + score--; + + /*if (CountUsablePartyMons(battlerAtk) != 0 + && GetMoveDamageResult(move) != 0 && !HasMoveWithSplit(battlerAtk, SPLIT_STATUS) + && GetCurrDamageHpPercent(battlerAtk, battlerDef) < 30) + { + if (GetCurrDamageHpPercent(battlerAtk, battlerDef) > 20) + score--; + else if (GetMoveDamageResult(move) == MOVE_POWER_BEST) + score -= 2; + else + score -= 3; + }*/ // check status move preference if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_PREFER_STATUS_MOVES && IS_MOVE_STATUS(move)) score++; - // check high crit - if (TestMoveFlags(move, FLAG_HIGH_CRIT) && effectiveness >= AI_EFFECTIVENESS_x2) - score++; - // check thawing moves if ((gBattleMons[battlerAtk].status1 & STATUS1_FREEZE) && IsThawingMove(move)) score += (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) ? 20 : 10; @@ -2783,71 +2777,257 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 8; // prioritize killing target for stat boost } break; - } // ability checks + case ABILITY_MAGIC_GUARD: + switch (moveEffect) + { + case EFFECT_POISON: + case EFFECT_WILL_O_WISP: + case EFFECT_TOXIC: + case EFFECT_LEECH_SEED: + score -= 5; + break; + case EFFECT_CURSE: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) + score -= 5; + break; + } + break; + } // ability checks // move effect checks switch (moveEffect) { + case EFFECT_HIT: break; case EFFECT_SLEEP: case EFFECT_YAWN: - IncreaseSleepScore(battlerAtk, battlerDef, move, &score); + if (AI_RandLessThan(128)) + IncreaseSleepScore(battlerAtk, battlerDef, move, &score); + break; + case EFFECT_ABSORB: + if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT) + score++; + if (typeEffectiveness <= AI_EFFECTIVENESS_x0_5 && AI_RandLessThan(50)) + score -= 3; + break; + case EFFECT_EXPLOSION: + case EFFECT_MEMENTO: + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7) + { + if (atkHpPercent < 50 && AI_RandLessThan(128)) + score++; + } + break; + case EFFECT_MIRROR_MOVE: + if (predictedMove != MOVE_NONE) + return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score); + break; +// stat raising effects + case EFFECT_ATTACK_UP: + case EFFECT_ATTACK_UP_2: + if (MovesWithSplitUnusable(battlerAtk, battlerDef, SPLIT_PHYSICAL)) + { + score -= 8; + break; + } + else if (gBattleMons[battlerAtk].statStages[STAT_ATK] < 9) + { + if (atkHpPercent > 90 && AI_RandLessThan(128)) + { + score += 2; + break; + } + } + + if (!AI_RandLessThan(100)) + { + score--; + } + break; + case EFFECT_DEFENSE_UP: + case EFFECT_DEFENSE_UP_2: + case EFFECT_DEFENSE_UP_3: + if (!HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) + score -= 2; + if (atkHpPercent > 90 && AI_RandLessThan(128)) + score += 2; + else if (atkHpPercent > 70 && AI_RandLessThan(200)) + break; + else if (atkHpPercent < 40) + score -= 2; + break; + case EFFECT_SPEED_UP: + case EFFECT_SPEED_UP_2: + if (IsAiFaster(AI_CHECK_SLOWER)) + { + if (!AI_RandLessThan(70)) + score += 3; + } + else + { + score -= 3; + } + break; + case EFFECT_SPECIAL_ATTACK_UP: + case EFFECT_SPECIAL_ATTACK_UP_2: + case EFFECT_SPECIAL_ATTACK_UP_3: + if (MovesWithSplitUnusable(battlerAtk, battlerDef, SPLIT_SPECIAL)) + { + score -= 8; + break; + } + else if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < 9) + { + if (atkHpPercent > 90 && AI_RandLessThan(128)) + { + score += 2; + break; + } + } + + if (!AI_RandLessThan(100)) + { + score--; + } + break; + case EFFECT_SPECIAL_DEFENSE_UP: + case EFFECT_SPECIAL_DEFENSE_UP_2: + if (!HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) + score -= 2; + if (atkHpPercent > 90 && AI_RandLessThan(128)) + score += 2; + else if (GetHealthPercentage(battlerAtk) > 70 && AI_RandLessThan(200)) + break; + else if (GetHealthPercentage(battlerAtk) < 40) + score -= 2; + break; + case EFFECT_ACCURACY_UP: + case EFFECT_ACCURACY_UP_2: + if (gBattleMons[battlerAtk].statStages[STAT_ACC] >= 9 && !AI_RandLessThan(50)) + score -= 2; + else if (atkHpPercent <= 70) + score -= 2; + else + score++; + break; + case EFFECT_EVASION_UP: + case EFFECT_EVASION_UP_2: + if (atkHpPercent > 90 && !AI_RandLessThan(100)) + score += 3; + if (gBattleMons[battlerAtk].statStages[STAT_EVASION] > 9 && AI_RandLessThan(128)) + score--; + if ((gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) && atkHpPercent >= 50 && !AI_RandLessThan(80)) + score += 3; + if (gStatuses3[battlerDef] & STATUS3_LEECHSEED && !AI_RandLessThan(70)) + score += 3; + if (gStatuses3[battlerAtk] & STATUS3_ROOTED && AI_RandLessThan(128)) + score += 2; + if (gBattleMons[battlerDef].status2 & STATUS2_CURSED && !AI_RandLessThan(70)) + score += 3; + if (atkHpPercent < 70 || gBattleMons[battlerAtk].statStages[STAT_EVASION] == DEFAULT_STAT_STAGE) + break; + else if (atkHpPercent < 40 || defHpPercent < 40) + score -= 2; + else if (!AI_RandLessThan(70)) + score -= 2; + break; +// stat lowering effects + case EFFECT_ATTACK_DOWN: + case EFFECT_ATTACK_DOWN_2: + if (!ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility)) + score -= 2; + if (gBattleMons[battlerDef].statStages[STAT_ATK] < DEFAULT_STAT_STAGE) + score--; + else if (atkHpPercent <= 90) + score--; + if (gBattleMons[battlerDef].statStages[STAT_ATK] > 3 && !AI_RandLessThan(50)) + score -= 2; + else if (defHpPercent < 70) + score -= 2; + break; + case EFFECT_DEFENSE_DOWN: + case EFFECT_DEFENSE_DOWN_2: + if (!ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility)) + score -= 2; + if ((atkHpPercent < 70 && !AI_RandLessThan(50)) || (gBattleMons[battlerDef].statStages[STAT_DEF] <= 3 && !AI_RandLessThan(50))) + score -= 2; + if (defHpPercent <= 70) + score -= 2; + break; + case EFFECT_SPEED_DOWN: + case EFFECT_SPEED_DOWN_2: + if (IsAiFaster(AI_CHECK_FASTER)) + score -= 3; + else if (!AI_RandLessThan(70)) + score += 2; + break; + case EFFECT_SPECIAL_ATTACK_DOWN: + case EFFECT_SPECIAL_ATTACK_DOWN_2: + if (!ShouldLowerSpAtk(battlerAtk, battlerDef, AI_DATA->defAbility)) + score -= 2; + if (gBattleMons[battlerDef].statStages[STAT_SPATK] < DEFAULT_STAT_STAGE) + score--; + else if (atkHpPercent <= 90) + score--; + if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 3 && !AI_RandLessThan(50)) + score -= 2; + else if (defHpPercent < 70) + score -= 2; + break; + case EFFECT_SPECIAL_DEFENSE_DOWN: + case EFFECT_SPECIAL_DEFENSE_DOWN_2: + if (!ShouldLowerSpDef(battlerAtk, battlerDef, AI_DATA->defAbility)) + score -= 2; + if ((atkHpPercent < 70 && !AI_RandLessThan(50)) + || (gBattleMons[battlerDef].statStages[STAT_SPDEF] <= 3 && !AI_RandLessThan(50))) + score -= 2; + if (defHpPercent <= 70) + score -= 2; + break; + case EFFECT_ACCURACY_DOWN: + case EFFECT_ACCURACY_DOWN_2: + if (ShouldLowerAccuracy(battlerAtk, battlerDef, AI_DATA->defAbility)) + score -= 2; + if ((atkHpPercent < 70 || defHpPercent < 70) && AI_RandLessThan(100)) + score--; + if (gBattleMons[battlerDef].statStages[STAT_ACC] <= 4 && !AI_RandLessThan(80)) + score -= 2; + if (gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY && !AI_RandLessThan(70)) + score += 2; + if (gStatuses3[battlerDef] & STATUS3_LEECHSEED && !AI_RandLessThan(70)) + score += 2; + if (gStatuses3[battlerDef] & STATUS3_ROOTED && AI_RandLessThan(128)) + score++; + if (gBattleMons[battlerDef].status2 & STATUS2_CURSED && !AI_RandLessThan(70)) + score += 2; + if (atkHpPercent > 70 || gBattleMons[battlerDef].statStages[STAT_ACC] < DEFAULT_STAT_STAGE) + break; + else if (atkHpPercent < 40 || defHpPercent < 40 || !AI_RandLessThan(70)) + score -= 2; + break; + case EFFECT_EVASION_DOWN: + case EFFECT_EVASION_DOWN_2: + if (!ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility)) + score -= 2; + if ((atkHpPercent < 70 || gBattleMons[battlerDef].statStages[STAT_EVASION] <= 3) && !AI_RandLessThan(50)) + score -= 2; + if (defHpPercent <= 70) + score -= 2; + if (gBattleMons[battlerAtk].statStages[STAT_ACC] < DEFAULT_STAT_STAGE) + score++; + if (gBattleMons[battlerDef].statStages[STAT_EVASION] < 7 || AI_DATA->atkAbility == ABILITY_NO_GUARD) + score -= 2; + break; + case EFFECT_BIDE: + if (atkHpPercent < 90) + score -= 2; break; case EFFECT_DREAM_EATER: if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) break; score++; // if target is asleep, dream eater is a pretty good move even without draining // fallthrough - case EFFECT_ABSORB: - if (ShouldAbsorb(battlerAtk, battlerDef, move, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex])) - score += 2; - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT) - score++; - break; - case EFFECT_EXPLOSION: - case EFFECT_MEMENTO: - if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7) - { - if (GetHealthPercentage(battlerAtk) < 50 && (Random() % 2)) - score++; - } - break; - case EFFECT_MIRROR_MOVE: - if (gLastMoves[battlerDef] != MOVE_NONE) - return AI_CheckGoodMove(battlerAtk, battlerDef, gLastMoves[battlerDef], score); - break; - case EFFECT_ATTACK_UP: - case EFFECT_ATTACK_UP_2: - IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score); - break; - case EFFECT_DEFENSE_UP: - case EFFECT_DEFENSE_UP_2: - case EFFECT_DEFENSE_UP_3: - IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score); - break; - case EFFECT_SPEED_UP: - case EFFECT_SPEED_UP_2: - IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score); - break; - case EFFECT_SPECIAL_ATTACK_UP: - case EFFECT_SPECIAL_ATTACK_UP_2: - case EFFECT_SPECIAL_ATTACK_UP_3: - IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score); - break; - case EFFECT_SPECIAL_DEFENSE_UP: - case EFFECT_SPECIAL_DEFENSE_UP_2: - IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score); - break; - case EFFECT_ACCURACY_UP: - case EFFECT_ACCURACY_UP_2: - IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ACC, &score); - break; - case EFFECT_EVASION_UP: - case EFFECT_EVASION_UP_2: - case EFFECT_MINIMIZE: - IncreaseStatUpScore(battlerAtk, battlerDef, STAT_EVASION, &score); - break; case EFFECT_ACUPRESSURE: break; case EFFECT_ATTACK_ACCURACY_UP: // hone claws @@ -2864,51 +3044,10 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) else if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score); break; - case EFFECT_ATTACK_DOWN: - case EFFECT_ATTACK_DOWN_2: - if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) - score += 2; - break; - case EFFECT_DEFENSE_DOWN: - case EFFECT_DEFENSE_DOWN_2: - if (ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) - score += 2; - break; - case EFFECT_SPEED_DOWN: - case EFFECT_SPEED_DOWN_2: - if (ShouldLowerSpeed(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) - score += 3; - break; - case EFFECT_SPECIAL_ATTACK_DOWN: - case EFFECT_SPECIAL_ATTACK_DOWN_2: - if (ShouldLowerSpAtk(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) - score += 2; - break; - case EFFECT_SPECIAL_DEFENSE_DOWN: - case EFFECT_SPECIAL_DEFENSE_DOWN_2: - if (ShouldLowerSpDef(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) - score += 2; - break; - case EFFECT_ACCURACY_DOWN: - case EFFECT_ACCURACY_DOWN_2: - if (ShouldLowerAccuracy(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) - score += 4; - break; - case EFFECT_EVASION_DOWN: - case EFFECT_EVASION_DOWN_2: - if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) - { - // kinda meh effect, so let's make sure we really want to - if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 7 - || HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) - score += 2; // encourage lowering evasion if they are evasive or we have a move with low accuracy - else - score++; - } - break; case EFFECT_HAZE: if (AnyStatIsRaised(AI_DATA->battlerAtkPartner) || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + score -= 3; break; // fallthrough case EFFECT_ROAR: @@ -2918,8 +3057,6 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) else score += min(CountPositiveStatStages(battlerDef), 4); break; - case EFFECT_BIDE: - break; case EFFECT_MULTI_HIT: case EFFECT_DOUBLE_HIT: case EFFECT_TRIPLE_KICK: @@ -3057,13 +3194,12 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; break; case EFFECT_SPEED_DOWN_HIT: - if (ShouldLowerSpeed(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) - { - if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY) - score += 4; - else - score += 2; - } + if (IsAiFaster(AI_CHECK_FASTER)) + score -= 2; + else if (!AI_RandLessThan(70)) + score++; + if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY) + score++; break; case EFFECT_SUBSTITUTE: if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) @@ -3085,7 +3221,7 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) { if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF) - return AI_CheckGoodMove(battlerAtk, battlerDef, gLastMoves[battlerDef], score); + return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score); } break; case EFFECT_LEECH_SEED: @@ -3605,7 +3741,7 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // check defog lowering evasion - if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility)) { if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 7 || HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) @@ -3639,7 +3775,7 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_NATURE_POWER: - return AI_CheckGoodMove(battlerAtk, battlerDef, GetNaturePowerMove(), score); + return AI_CheckViability(battlerAtk, battlerDef, GetNaturePowerMove(), score); case EFFECT_CHARGE: if (HasDamagingMoveOfType(battlerAtk, TYPE_ELECTRIC)) score += 2; @@ -3850,11 +3986,11 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_TICKLE: if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) - && AI_DATA->defAbility != ABILITY_CONTRARY && ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + && AI_DATA->defAbility != ABILITY_CONTRARY && ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility)) { score += 2; } - else if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex)) + else if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility)) { score += 2; } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index f7c846c0b8..4897f93d64 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -436,6 +436,13 @@ static const u16 sOtherMoveCallingMoves[] = }; // Functions +bool32 AI_RandLessThan(u8 val) +{ + if ((Random() % 0xFF) < val) + return TRUE; + return FALSE; +} + void RecordLastUsedMoveByTarget(void) { RecordKnownMove(gBattlerTarget, gLastMoves[gBattlerTarget]); @@ -857,6 +864,13 @@ u8 GetMoveDamageResult(u16 move) return AI_THINKING_STRUCT->funcResult; } +u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef) +{ + int bestDmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + + return (bestDmg * 100) / gBattleMons[battlerDef].maxHP; +} + u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) { u8 damageVar; @@ -1583,9 +1597,9 @@ u32 CountNegativeStatStages(u8 battlerId) return count; } -bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4 @@ -1599,9 +1613,9 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIn return FALSE; } -bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 @@ -1615,9 +1629,9 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveI return FALSE; } -bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (IsAiFaster(AI_CHECK_SLOWER) @@ -1629,9 +1643,9 @@ bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveInd return FALSE; } -bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4 @@ -1644,9 +1658,9 @@ bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveInd return FALSE; } -bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4 @@ -1659,9 +1673,9 @@ bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveInd return FALSE; } -bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (defAbility != ABILITY_CONTRARY @@ -1673,9 +1687,9 @@ bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 move return FALSE; } -bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex) +bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE @@ -3228,6 +3242,9 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) if (AI_DATA->atkAbility == ABILITY_CONTRARY) return; + if (GetHealthPercentage(battlerAtk) < 80 && AI_RandLessThan(128)) + return; + switch (statId) { case STAT_ATK: @@ -3304,16 +3321,16 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) if (!HasDamagingMove(battlerDef)) *score += 2; - if (HasMoveEffect(battlerAtk, EFFECT_PROTECT)) + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT)) (*score)++; // stall tactic if (HasMoveEffect(battlerAtk, EFFECT_VENOSHOCK) || HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH) || AI_DATA->atkAbility == ABILITY_MERCILESS) - *score += 4; + *(score) += 2; else - *score += 2; + *(score)++; } } @@ -3354,8 +3371,10 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) - *score += 3; - + *score += 2; + else + return; + if ((HasMoveEffect(battlerAtk, EFFECT_DREAM_EATER) || HasMoveEffect(battlerAtk, EFFECT_NIGHTMARE)) && !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) (*score)++; diff --git a/src/battle_factory.c b/src/battle_factory.c index e54796196b..98af96664c 100644 --- a/src/battle_factory.c +++ b/src/battle_factory.c @@ -850,13 +850,13 @@ u32 GetAiScriptsInBattleFactory(void) int challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7; if (gTrainerBattleOpponent_A == TRAINER_FRONTIER_BRAIN) - return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE; + return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY; else if (challengeNum < 2) return 0; else if (challengeNum < 4) return AI_FLAG_CHECK_BAD_MOVE; else - return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE; + return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY; } } diff --git a/src/data/trainers.h b/src/data/trainers.h index 5712fc1442..619763ea11 100644 --- a/src/data/trainers.h +++ b/src/data/trainers.h @@ -22,7 +22,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer1), .party = {.NoItemDefaultMoves = sParty_Sawyer1}, }, @@ -162,7 +162,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARCEL"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Marcel), .party = {.NoItemDefaultMoves = sParty_Marcel}, }, @@ -414,7 +414,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FREDRICK"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Fredrick), .party = {.NoItemDefaultMoves = sParty_Fredrick}, }, @@ -428,7 +428,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MATT"), .items = {ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Matt), .party = {.NoItemDefaultMoves = sParty_Matt}, }, @@ -456,7 +456,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_ShellyWeatherInstitute), .party = {.NoItemDefaultMoves = sParty_ShellyWeatherInstitute}, }, @@ -470,7 +470,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_ShellySeafloorCavern), .party = {.NoItemDefaultMoves = sParty_ShellySeafloorCavern}, }, @@ -484,7 +484,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ARCHIE"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Archie), .party = {.NoItemDefaultMoves = sParty_Archie}, }, @@ -540,7 +540,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FELIX"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Felix), .party = {.NoItemCustomMoves = sParty_Felix}, }, @@ -1002,7 +1002,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RANDALL"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Randall), .party = {.ItemCustomMoves = sParty_Randall}, }, @@ -1016,7 +1016,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PARKER"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Parker), .party = {.ItemCustomMoves = sParty_Parker}, }, @@ -1030,7 +1030,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GEORGE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_George), .party = {.ItemCustomMoves = sParty_George}, }, @@ -1044,7 +1044,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BERKE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Berke), .party = {.ItemCustomMoves = sParty_Berke}, }, @@ -1058,7 +1058,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAXTON"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Braxton), .party = {.NoItemCustomMoves = sParty_Braxton}, }, @@ -1072,7 +1072,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VINCENT"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Vincent), .party = {.NoItemDefaultMoves = sParty_Vincent}, }, @@ -1086,7 +1086,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEROY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Leroy), .party = {.NoItemDefaultMoves = sParty_Leroy}, }, @@ -1100,7 +1100,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton1), .party = {.NoItemDefaultMoves = sParty_Wilton1}, }, @@ -1114,7 +1114,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("EDGAR"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Edgar), .party = {.NoItemDefaultMoves = sParty_Edgar}, }, @@ -1128,7 +1128,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALBERT"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Albert), .party = {.NoItemDefaultMoves = sParty_Albert}, }, @@ -1142,7 +1142,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAMUEL"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Samuel), .party = {.NoItemDefaultMoves = sParty_Samuel}, }, @@ -1156,7 +1156,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VITO"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Vito), .party = {.NoItemDefaultMoves = sParty_Vito}, }, @@ -1170,7 +1170,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("OWEN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Owen), .party = {.NoItemDefaultMoves = sParty_Owen}, }, @@ -1184,7 +1184,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton2), .party = {.NoItemDefaultMoves = sParty_Wilton2}, }, @@ -1198,7 +1198,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton3), .party = {.NoItemDefaultMoves = sParty_Wilton3}, }, @@ -1212,7 +1212,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton4), .party = {.NoItemDefaultMoves = sParty_Wilton4}, }, @@ -1226,7 +1226,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WILTON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wilton5), .party = {.NoItemDefaultMoves = sParty_Wilton5}, }, @@ -1240,7 +1240,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WARREN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Warren), .party = {.NoItemDefaultMoves = sParty_Warren}, }, @@ -1254,7 +1254,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Mary), .party = {.ItemCustomMoves = sParty_Mary}, }, @@ -1268,7 +1268,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEXIA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Alexia), .party = {.ItemCustomMoves = sParty_Alexia}, }, @@ -1324,7 +1324,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke1), .party = {.NoItemDefaultMoves = sParty_Brooke1}, }, @@ -1338,7 +1338,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JENNIFER"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jennifer), .party = {.NoItemDefaultMoves = sParty_Jennifer}, }, @@ -1352,7 +1352,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HOPE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Hope), .party = {.NoItemDefaultMoves = sParty_Hope}, }, @@ -1366,7 +1366,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHANNON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shannon), .party = {.NoItemDefaultMoves = sParty_Shannon}, }, @@ -1380,7 +1380,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MICHELLE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Michelle), .party = {.NoItemDefaultMoves = sParty_Michelle}, }, @@ -1394,7 +1394,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAROLINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Caroline), .party = {.NoItemDefaultMoves = sParty_Caroline}, }, @@ -1408,7 +1408,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JULIE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Julie), .party = {.NoItemDefaultMoves = sParty_Julie}, }, @@ -1422,7 +1422,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke2), .party = {.NoItemDefaultMoves = sParty_Brooke2}, }, @@ -1436,7 +1436,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke3), .party = {.NoItemDefaultMoves = sParty_Brooke3}, }, @@ -1450,7 +1450,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke4), .party = {.NoItemDefaultMoves = sParty_Brooke4}, }, @@ -1464,7 +1464,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BROOKE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brooke5), .party = {.NoItemDefaultMoves = sParty_Brooke5}, }, @@ -3662,7 +3662,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SIDNEY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_SETUP_FIRST_TURN, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SETUP_FIRST_TURN, .partySize = ARRAY_COUNT(sParty_Sidney), .party = {.ItemCustomMoves = sParty_Sidney}, }, @@ -3676,7 +3676,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PHOEBE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Phoebe), .party = {.ItemCustomMoves = sParty_Phoebe}, }, @@ -3690,7 +3690,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GLACIA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Glacia), .party = {.ItemCustomMoves = sParty_Glacia}, }, @@ -3704,7 +3704,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DRAKE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Drake), .party = {.ItemCustomMoves = sParty_Drake}, }, @@ -3718,7 +3718,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_POTION, ITEM_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne1), .party = {.ItemCustomMoves = sParty_Roxanne1}, }, @@ -3732,7 +3732,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly1), .party = {.ItemCustomMoves = sParty_Brawly1}, }, @@ -3746,7 +3746,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson1), .party = {.ItemCustomMoves = sParty_Wattson1}, }, @@ -3760,7 +3760,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery1), .party = {.ItemCustomMoves = sParty_Flannery1}, }, @@ -3774,7 +3774,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman1), .party = {.ItemCustomMoves = sParty_Norman1}, }, @@ -3788,7 +3788,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona1), .party = {.ItemCustomMoves = sParty_Winona1}, }, @@ -3802,7 +3802,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_HYPER_POTION}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza1), .party = {.ItemCustomMoves = sParty_TateAndLiza1}, }, @@ -3816,7 +3816,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_HYPER_POTION, ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan1), .party = {.ItemCustomMoves = sParty_Juan1}, }, @@ -4306,7 +4306,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy1), .party = {.NoItemDefaultMoves = sParty_Timothy1}, }, @@ -4320,7 +4320,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy2), .party = {.NoItemCustomMoves = sParty_Timothy2}, }, @@ -4334,7 +4334,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy3), .party = {.NoItemCustomMoves = sParty_Timothy3}, }, @@ -4348,7 +4348,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy4), .party = {.NoItemCustomMoves = sParty_Timothy4}, }, @@ -4362,7 +4362,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TIMOTHY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Timothy5), .party = {.NoItemCustomMoves = sParty_Timothy5}, }, @@ -4376,7 +4376,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VICKY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Vicky), .party = {.NoItemCustomMoves = sParty_Vicky}, }, @@ -4390,7 +4390,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby1), .party = {.NoItemDefaultMoves = sParty_Shelby1}, }, @@ -4404,7 +4404,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby2), .party = {.NoItemDefaultMoves = sParty_Shelby2}, }, @@ -4418,7 +4418,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby3), .party = {.NoItemDefaultMoves = sParty_Shelby3}, }, @@ -4432,7 +4432,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby4), .party = {.NoItemDefaultMoves = sParty_Shelby4}, }, @@ -4446,7 +4446,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SHELBY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Shelby5), .party = {.NoItemDefaultMoves = sParty_Shelby5}, }, @@ -4544,7 +4544,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("QUINCY"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Quincy), .party = {.NoItemCustomMoves = sParty_Quincy}, }, @@ -4558,7 +4558,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("KATELYNN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Katelynn), .party = {.NoItemCustomMoves = sParty_Katelynn}, }, @@ -4698,7 +4698,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLACE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wallace), .party = {.ItemCustomMoves = sParty_Wallace}, }, @@ -7050,7 +7050,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JAZMYN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jazmyn), .party = {.NoItemDefaultMoves = sParty_Jazmyn}, }, @@ -7064,7 +7064,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JONAS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jonas), .party = {.NoItemCustomMoves = sParty_Jonas}, }, @@ -7120,7 +7120,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MARLEY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Marley), .party = {.ItemCustomMoves = sParty_Marley}, }, @@ -7274,7 +7274,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR1), .party = {.NoItemCustomMoves = sParty_WallyVR1}, }, @@ -7288,7 +7288,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute103Mudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRoute103Mudkip}, }, @@ -7302,7 +7302,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute110Mudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRoute110Mudkip}, }, @@ -7316,7 +7316,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute119Mudkip), .party = {.NoItemDefaultMoves = sParty_BrendanRoute119Mudkip}, }, @@ -7344,7 +7344,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute110Treecko), .party = {.NoItemDefaultMoves = sParty_BrendanRoute110Treecko}, }, @@ -7358,7 +7358,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute119Treecko), .party = {.NoItemDefaultMoves = sParty_BrendanRoute119Treecko}, }, @@ -7372,7 +7372,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute103Torchic), .party = {.NoItemDefaultMoves = sParty_BrendanRoute103Torchic}, }, @@ -7386,7 +7386,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute110Torchic), .party = {.NoItemDefaultMoves = sParty_BrendanRoute110Torchic}, }, @@ -7400,7 +7400,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRoute119Torchic), .party = {.NoItemDefaultMoves = sParty_BrendanRoute119Torchic}, }, @@ -7414,7 +7414,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute103Mudkip), .party = {.NoItemDefaultMoves = sParty_MayRoute103Mudkip}, }, @@ -7428,7 +7428,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute110Mudkip), .party = {.NoItemDefaultMoves = sParty_MayRoute110Mudkip}, }, @@ -7442,7 +7442,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute119Mudkip), .party = {.NoItemDefaultMoves = sParty_MayRoute119Mudkip}, }, @@ -7456,7 +7456,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute103Treecko), .party = {.NoItemDefaultMoves = sParty_MayRoute103Treecko}, }, @@ -7470,7 +7470,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute110Treecko), .party = {.NoItemDefaultMoves = sParty_MayRoute110Treecko}, }, @@ -7484,7 +7484,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute119Treecko), .party = {.NoItemDefaultMoves = sParty_MayRoute119Treecko}, }, @@ -7498,7 +7498,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute103Torchic), .party = {.NoItemDefaultMoves = sParty_MayRoute103Torchic}, }, @@ -7512,7 +7512,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute110Torchic), .party = {.NoItemDefaultMoves = sParty_MayRoute110Torchic}, }, @@ -7526,7 +7526,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRoute119Torchic), .party = {.NoItemDefaultMoves = sParty_MayRoute119Torchic}, }, @@ -7568,7 +7568,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MITCHELL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Mitchell), .party = {.NoItemCustomMoves = sParty_Mitchell}, }, @@ -7652,7 +7652,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("HALLE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Halle), .party = {.NoItemDefaultMoves = sParty_Halle}, }, @@ -7736,7 +7736,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jackson1), .party = {.NoItemDefaultMoves = sParty_Jackson1}, }, @@ -7750,7 +7750,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LORENZO"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Lorenzo), .party = {.NoItemDefaultMoves = sParty_Lorenzo}, }, @@ -7764,7 +7764,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SEBASTIAN"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sebastian), .party = {.NoItemDefaultMoves = sParty_Sebastian}, }, @@ -7792,7 +7792,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jackson3), .party = {.NoItemDefaultMoves = sParty_Jackson3}, }, @@ -7820,7 +7820,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JACKSON"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Jackson5), .party = {.NoItemDefaultMoves = sParty_Jackson5}, }, @@ -7862,7 +7862,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SOPHIA"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sophia), .party = {.NoItemDefaultMoves = sParty_Sophia}, }, @@ -7890,7 +7890,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CATHERINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Catherine3), .party = {.NoItemDefaultMoves = sParty_Catherine3}, }, @@ -7918,7 +7918,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CATHERINE"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Catherine5), .party = {.NoItemDefaultMoves = sParty_Catherine5}, }, @@ -8086,7 +8086,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ATHENA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Athena), .party = {.ItemCustomMoves = sParty_Athena}, }, @@ -8324,7 +8324,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("PAXTON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Paxton), .party = {.NoItemDefaultMoves = sParty_Paxton}, }, @@ -8366,7 +8366,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TABITHA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TabithaMtChimney), .party = {.NoItemDefaultMoves = sParty_TabithaMtChimney}, }, @@ -8394,7 +8394,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanRustboroTorchic), .party = {.NoItemDefaultMoves = sParty_BrendanRustboroTorchic}, }, @@ -8422,7 +8422,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAXIE"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MaxieMagmaHideout), .party = {.NoItemDefaultMoves = sParty_MaxieMagmaHideout}, }, @@ -8436,7 +8436,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAXIE"), .items = {ITEM_SUPER_POTION, ITEM_SUPER_POTION, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MaxieMtChimney), .party = {.NoItemDefaultMoves = sParty_MaxieMtChimney}, }, @@ -8492,7 +8492,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("VIVI"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Vivi), .party = {.NoItemDefaultMoves = sParty_Vivi}, }, @@ -9080,7 +9080,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GERALD"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Gerald), .party = {.NoItemCustomMoves = sParty_Gerald}, }, @@ -9192,7 +9192,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyMauville), .party = {.NoItemDefaultMoves = sParty_WallyMauville}, }, @@ -9206,7 +9206,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR2), .party = {.NoItemCustomMoves = sParty_WallyVR2}, }, @@ -9220,7 +9220,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR3), .party = {.NoItemCustomMoves = sParty_WallyVR3}, }, @@ -9234,7 +9234,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR4), .party = {.NoItemCustomMoves = sParty_WallyVR4}, }, @@ -9248,7 +9248,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WALLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_WallyVR5), .party = {.NoItemCustomMoves = sParty_WallyVR5}, }, @@ -9262,7 +9262,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanLilycoveMudkip), .party = {.NoItemDefaultMoves = sParty_BrendanLilycoveMudkip}, }, @@ -9276,7 +9276,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanLilycoveTreecko), .party = {.NoItemDefaultMoves = sParty_BrendanLilycoveTreecko}, }, @@ -9290,7 +9290,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRENDAN"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_BrendanLilycoveTorchic), .party = {.NoItemDefaultMoves = sParty_BrendanLilycoveTorchic}, }, @@ -9304,7 +9304,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayLilycoveMudkip), .party = {.NoItemDefaultMoves = sParty_MayLilycoveMudkip}, }, @@ -9318,7 +9318,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayLilycoveTreecko), .party = {.NoItemDefaultMoves = sParty_MayLilycoveTreecko}, }, @@ -9332,7 +9332,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayLilycoveTorchic), .party = {.NoItemDefaultMoves = sParty_MayLilycoveTorchic}, }, @@ -9388,7 +9388,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ALEXA"), .items = {ITEM_FULL_RESTORE, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Alexa), .party = {.NoItemDefaultMoves = sParty_Alexa}, }, @@ -9402,7 +9402,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("RUBEN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Ruben), .party = {.NoItemDefaultMoves = sParty_Ruben}, }, @@ -9542,7 +9542,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_JohnAndJay1), .party = {.NoItemCustomMoves = sParty_JohnAndJay1}, }, @@ -9556,7 +9556,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_JohnAndJay2), .party = {.NoItemCustomMoves = sParty_JohnAndJay2}, }, @@ -9570,7 +9570,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_JohnAndJay3), .party = {.NoItemCustomMoves = sParty_JohnAndJay3}, }, @@ -9598,7 +9598,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JOHN & JAY"), .items = {}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_JohnAndJay5), .party = {.NoItemCustomMoves = sParty_JohnAndJay5}, }, @@ -10270,7 +10270,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARCY"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Darcy), .party = {.NoItemDefaultMoves = sParty_Darcy}, }, @@ -10284,7 +10284,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAXIE"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MaxieMossdeep), .party = {.NoItemDefaultMoves = sParty_MaxieMossdeep}, }, @@ -10382,7 +10382,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CAROLINA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Carolina), .party = {.NoItemDefaultMoves = sParty_Carolina}, }, @@ -10620,7 +10620,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAKAYLA"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Makayla), .party = {.NoItemDefaultMoves = sParty_Makayla}, }, @@ -10676,7 +10676,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LEONEL"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Leonel), .party = {.NoItemCustomMoves = sParty_Leonel}, }, @@ -10746,7 +10746,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin1), .party = {.NoItemDefaultMoves = sParty_Cristin1}, }, @@ -10760,7 +10760,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRustboroTreecko), .party = {.NoItemDefaultMoves = sParty_MayRustboroTreecko}, }, @@ -10774,7 +10774,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("MAY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_MayRustboroTorchic), .party = {.NoItemDefaultMoves = sParty_MayRustboroTorchic}, }, @@ -10788,7 +10788,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne2), .party = {.ItemCustomMoves = sParty_Roxanne2}, }, @@ -10802,7 +10802,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne3), .party = {.ItemCustomMoves = sParty_Roxanne3}, }, @@ -10816,7 +10816,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne4), .party = {.ItemCustomMoves = sParty_Roxanne4}, }, @@ -10830,7 +10830,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ROXANNE"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Roxanne5), .party = {.ItemCustomMoves = sParty_Roxanne5}, }, @@ -10844,7 +10844,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly2), .party = {.ItemCustomMoves = sParty_Brawly2}, }, @@ -10858,7 +10858,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly3), .party = {.ItemCustomMoves = sParty_Brawly3}, }, @@ -10872,7 +10872,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly4), .party = {.ItemCustomMoves = sParty_Brawly4}, }, @@ -10886,7 +10886,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRAWLY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brawly5), .party = {.ItemCustomMoves = sParty_Brawly5}, }, @@ -10900,7 +10900,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson2), .party = {.ItemCustomMoves = sParty_Wattson2}, }, @@ -10914,7 +10914,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson3), .party = {.ItemCustomMoves = sParty_Wattson3}, }, @@ -10928,7 +10928,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson4), .party = {.ItemCustomMoves = sParty_Wattson4}, }, @@ -10942,7 +10942,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WATTSON"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Wattson5), .party = {.ItemCustomMoves = sParty_Wattson5}, }, @@ -10956,7 +10956,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery2), .party = {.ItemCustomMoves = sParty_Flannery2}, }, @@ -10970,7 +10970,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery3), .party = {.ItemCustomMoves = sParty_Flannery3}, }, @@ -10984,7 +10984,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery4), .party = {.ItemCustomMoves = sParty_Flannery4}, }, @@ -10998,7 +10998,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("FLANNERY"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Flannery5), .party = {.ItemCustomMoves = sParty_Flannery5}, }, @@ -11012,7 +11012,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman2), .party = {.ItemCustomMoves = sParty_Norman2}, }, @@ -11026,7 +11026,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman3), .party = {.ItemCustomMoves = sParty_Norman3}, }, @@ -11040,7 +11040,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman4), .party = {.ItemCustomMoves = sParty_Norman4}, }, @@ -11054,7 +11054,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NORMAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Norman5), .party = {.ItemCustomMoves = sParty_Norman5}, }, @@ -11068,7 +11068,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona2), .party = {.ItemCustomMoves = sParty_Winona2}, }, @@ -11082,7 +11082,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona3), .party = {.ItemCustomMoves = sParty_Winona3}, }, @@ -11096,7 +11096,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona4), .party = {.ItemCustomMoves = sParty_Winona4}, }, @@ -11110,7 +11110,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("WINONA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_RISKY, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY, .partySize = ARRAY_COUNT(sParty_Winona5), .party = {.ItemCustomMoves = sParty_Winona5}, }, @@ -11124,7 +11124,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza2), .party = {.ItemCustomMoves = sParty_TateAndLiza2}, }, @@ -11138,7 +11138,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza3), .party = {.ItemCustomMoves = sParty_TateAndLiza3}, }, @@ -11152,7 +11152,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza4), .party = {.ItemCustomMoves = sParty_TateAndLiza4}, }, @@ -11166,7 +11166,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TATE&LIZA"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_TateAndLiza5), .party = {.ItemCustomMoves = sParty_TateAndLiza5}, }, @@ -11180,7 +11180,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan2), .party = {.ItemCustomMoves = sParty_Juan2}, }, @@ -11194,7 +11194,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan3), .party = {.ItemCustomMoves = sParty_Juan3}, }, @@ -11208,7 +11208,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan4), .party = {.ItemCustomMoves = sParty_Juan4}, }, @@ -11222,7 +11222,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("JUAN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_NONE}, .doubleBattle = TRUE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Juan5), .party = {.ItemCustomMoves = sParty_Juan5}, }, @@ -11236,7 +11236,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANGELO"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Angelo), .party = {.ItemCustomMoves = sParty_Angelo}, }, @@ -11250,7 +11250,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("DARIUS"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Darius), .party = {.NoItemDefaultMoves = sParty_Darius}, }, @@ -11264,7 +11264,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("STEVEN"), .items = {ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE, ITEM_FULL_RESTORE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Steven), .party = {.ItemCustomMoves = sParty_Steven}, }, @@ -11278,7 +11278,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("ANABEL"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Anabel), .party = {.NoItemDefaultMoves = sParty_Anabel}, }, @@ -11292,7 +11292,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("TUCKER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Tucker), .party = {.NoItemDefaultMoves = sParty_Tucker}, }, @@ -11306,7 +11306,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SPENSER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Spenser), .party = {.NoItemDefaultMoves = sParty_Spenser}, }, @@ -11320,7 +11320,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("GRETA"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Greta), .party = {.NoItemDefaultMoves = sParty_Greta}, }, @@ -11334,7 +11334,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("NOLAND"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Noland), .party = {.NoItemDefaultMoves = sParty_Noland}, }, @@ -11348,7 +11348,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("LUCY"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Lucy), .party = {.NoItemDefaultMoves = sParty_Lucy}, }, @@ -11362,7 +11362,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("BRANDON"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Brandon), .party = {.NoItemDefaultMoves = sParty_Brandon}, }, @@ -11600,7 +11600,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin2), .party = {.NoItemDefaultMoves = sParty_Cristin2}, }, @@ -11614,7 +11614,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin3), .party = {.NoItemDefaultMoves = sParty_Cristin3}, }, @@ -11628,7 +11628,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin4), .party = {.NoItemDefaultMoves = sParty_Cristin4}, }, @@ -11642,7 +11642,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("CRISTIN"), .items = {ITEM_HYPER_POTION, ITEM_NONE, ITEM_NONE, ITEM_NONE}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Cristin5), .party = {.NoItemDefaultMoves = sParty_Cristin5}, }, @@ -11712,7 +11712,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer2), .party = {.NoItemDefaultMoves = sParty_Sawyer2}, }, @@ -11726,7 +11726,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer3), .party = {.NoItemDefaultMoves = sParty_Sawyer3}, }, @@ -11740,7 +11740,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer4), .party = {.NoItemDefaultMoves = sParty_Sawyer4}, }, @@ -11754,7 +11754,7 @@ const struct Trainer gTrainers[] = { .trainerName = _("SAWYER"), .items = {}, .doubleBattle = FALSE, - .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE, + .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .partySize = ARRAY_COUNT(sParty_Sawyer5), .party = {.NoItemDefaultMoves = sParty_Sawyer5}, }, diff --git a/src/trainer_hill.c b/src/trainer_hill.c index d7b4ee37ac..043522aee1 100644 --- a/src/trainer_hill.c +++ b/src/trainer_hill.c @@ -897,7 +897,7 @@ void FillHillTrainersParties(void) // hill trainers. u32 GetTrainerHillAIFlags(void) { - return (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE); + return (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); } u8 GetTrainerEncounterMusicIdInTrainerHill(u16 trainerId) From 81c56a224a3ad75d16ab9f7ab561c400440368a1 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 4 Jan 2021 20:23:09 -0700 Subject: [PATCH 17/36] fix bad ai util func --- src/battle_ai_main.c | 22 ++++++++++++------- src/battle_ai_util.c | 51 +++++++++++++++++--------------------------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 8ccb05640f..0b60efb6a8 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -516,7 +516,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u8 moveTarget = gBattleMoves[move].target; u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); u8 effectiveness = AI_GetMoveEffectiveness(move); - u8 typeEffectiveness = AI_GetTypeEffectiveness(move, battlerAtk, battlerDef); bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); u32 i; u16 predictedMove = gLastMoves[battlerDef]; // TODO better move prediction @@ -548,7 +547,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // check if negates type - if (!IS_MOVE_STATUS(move) && (effectiveness == AI_EFFECTIVENESS_x0 || typeEffectiveness == AI_EFFECTIVENESS_x0)) + if (!IS_MOVE_STATUS(move) && (effectiveness == AI_EFFECTIVENESS_x0 || effectiveness == AI_EFFECTIVENESS_x0)) score -= 10; // target ability checks @@ -756,7 +755,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE)) score -= 2; - if (typeEffectiveness == AI_EFFECTIVENESS_x0) + if (effectiveness == AI_EFFECTIVENESS_x0) { score -= 10; } @@ -775,7 +774,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_DREAM_EATER: if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP) || AI_DATA->defAbility == ABILITY_COMATOSE) score -= 8; - else if (typeEffectiveness == AI_EFFECTIVENESS_x0) + else if (effectiveness == AI_EFFECTIVENESS_x0) score -= 10; break; // stat raising effects @@ -1112,7 +1111,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) //case EFFECT_ENDEAVOR: case EFFECT_LOW_KICK: // AI_CBM_HighRiskForDamage - if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && typeEffectiveness < AI_EFFECTIVENESS_x2) + if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) score -= 10; break; case EFFECT_COUNTER: @@ -1652,7 +1651,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 6; break; case EFFECT_RECHARGE: - if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && typeEffectiveness < AI_EFFECTIVENESS_x2) + if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) score -= 10; else if (AI_DATA->atkAbility != ABILITY_TRUANT && !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) @@ -2706,7 +2705,6 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // move data u16 moveEffect = gBattleMoves[move].effect; u8 effectiveness = AI_GetMoveEffectiveness(move); - u8 typeEffectiveness = AI_GetTypeEffectiveness(move, battlerAtk, battlerDef); u8 atkPriority = GetMovePriority(battlerAtk, move); u16 predictedMove = gLastMoves[battlerDef]; //for now bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); @@ -2808,7 +2806,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_ABSORB: if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT) score++; - if (typeEffectiveness <= AI_EFFECTIVENESS_x0_5 && AI_RandLessThan(50)) + if (effectiveness <= AI_EFFECTIVENESS_x0_5 && AI_RandLessThan(50)) score -= 3; break; case EFFECT_EXPLOSION: @@ -3201,6 +3199,14 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY) score++; break; + if (ShouldLowerSpeed(battlerAtk, battlerDef, AI_DATA->defAbility)) + { + if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY) + score += 4; + else + score += 2; + } + break; case EFFECT_SUBSTITUTE: if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) score += 3; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 4897f93d64..5e7cbadf75 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -873,36 +873,23 @@ u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef) u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) { - u8 damageVar; - u32 effectivenessMultiplier; + u16 typeEffectiveness, moveType; - gMoveResultFlags = 0; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, sBattler_AI, gBattlerTarget); - switch (effectivenessMultiplier) - { - case UQ_4_12(0.0): - default: - damageVar = AI_EFFECTIVENESS_x0; - break; - case UQ_4_12(0.25): - damageVar = AI_EFFECTIVENESS_x0_25; - break; - case UQ_4_12(0.5): - damageVar = AI_EFFECTIVENESS_x0_5; - break; - case UQ_4_12(1.0): - damageVar = AI_EFFECTIVENESS_x1; - break; - case UQ_4_12(2.0): - damageVar = AI_EFFECTIVENESS_x2; - break; - case UQ_4_12(4.0): - damageVar = AI_EFFECTIVENESS_x4; - break; - } + SaveBattlerData(battlerAtk); + SaveBattlerData(battlerDef); - return damageVar; + SetBattlerData(battlerAtk); + SetBattlerData(battlerDef); + + gBattleStruct->dynamicMoveType = 0; + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, FALSE); + + RestoreBattlerData(battlerAtk); + RestoreBattlerData(battlerDef); + + return typeEffectiveness; } u8 AI_GetMoveEffectiveness(u16 move) @@ -3298,17 +3285,17 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) break; case STAT_ACC: if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) - *score += 3; // has moves with less than 80% accuracy + *score += 2; // has moves with less than 80% accuracy else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) - *score += 2; + *(score)++; break; case STAT_EVASION: if (!BattlerWillFaintFromWeather(battlerAtk, AI_DATA->atkAbility)) { if (!GetBattlerSecondaryDamage(battlerAtk) && !(gStatuses3[battlerAtk] & STATUS3_ROOTED)) - *score += 3; - else *score += 2; + else + *(score)++; } break; } From bb540b62368f3eec54c9bf4bcc3cafc2c10769ac Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 10 Jan 2021 08:58:41 -0700 Subject: [PATCH 18/36] fix AI_WeatherHasEffect to handle unknown abilities --- src/battle_ai_util.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 5e7cbadf75..b43599f7b3 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1128,10 +1128,18 @@ bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move) bool32 AI_WeatherHasEffect(void) { + u32 i; if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) - return FALSE; // AI doesn't understand ability suppression concept + return FALSE; // AI doesn't understand weather supression (handicap) - return WEATHER_HAS_EFFECT; + // need to manually check since we don't necessarily know opponent ability + for (i = 0; i < gBattlersCount; i++) + { + if (IsBattlerAlive(i) + && (AI_GetAbility(i) == ABILITY_AIR_LOCK || AI_GetAbility(i) == ABILITY_CLOUD_NINE) + return TRUE; + } + return FALSE; } bool32 IsAromaVeilProtectedMove(u16 move) From 6a3266a26591b37cfd35841507ca0e6503759853 Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 10 Jan 2021 09:02:06 -0700 Subject: [PATCH 19/36] fix syntax err --- src/battle_ai_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index b43599f7b3..71563b665f 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1136,7 +1136,7 @@ bool32 AI_WeatherHasEffect(void) for (i = 0; i < gBattlersCount; i++) { if (IsBattlerAlive(i) - && (AI_GetAbility(i) == ABILITY_AIR_LOCK || AI_GetAbility(i) == ABILITY_CLOUD_NINE) + && (AI_GetAbility(i) == ABILITY_AIR_LOCK || AI_GetAbility(i) == ABILITY_CLOUD_NINE)) return TRUE; } return FALSE; From 47bf5b2840d1a024bb27a1b7753598fe544103c6 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 12 Jan 2021 22:45:02 -0700 Subject: [PATCH 20/36] a few tweaks --- src/battle_ai_main.c | 9 ++++----- src/battle_ai_util.c | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 0b60efb6a8..2df626d2d7 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -363,7 +363,7 @@ static u8 ChooseMoveOrAction_Doubles(void) if (gBattleTypeFlags & BATTLE_TYPE_PALACE) BattleAI_SetupAIData(gBattleStruct->palaceFlags >> 4); else - BattleAI_SetupAIData((1 << MAX_MON_MOVES) - 1); + BattleAI_SetupAIData(0xF); gBattlerTarget = i; GetAiLogicData(sBattler_AI, gBattlerTarget); @@ -1741,18 +1741,17 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (decreased) break; - if (gBattleMons[battlerDef].status2 & STATUS2_RECHARGE) + if (IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility)) { score -= 10; break; } - if (gBattleMoves[gLastResultingMoves[battlerAtk]].effect == EFFECT_PROTECT - && move != MOVE_QUICK_GUARD + if (move != MOVE_QUICK_GUARD && move != MOVE_WIDE_GUARD && move != MOVE_CRAFTY_SHIELD) //These moves have infinite usage { - if (GetBattlerSecondaryDamage(battlerAtk) + if (GetBattlerSecondaryDamage(battlerAtk) >= gBattleMons[battlerAtk].hp && AI_DATA->defAbility != ABILITY_MOXIE && AI_DATA->defAbility != ABILITY_BEAST_BOOST) { diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 71563b665f..676091675e 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -2643,7 +2643,7 @@ bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGe || atkGender == defGender || atkGender == MON_GENDERLESS || defGender == MON_GENDERLESS - || !IsAbilityOnSide(battlerDef, ABILITY_AROMA_VEIL)) + || IsAbilityOnSide(battlerDef, ABILITY_AROMA_VEIL)) return FALSE; return TRUE; } From 09dc1b7e891cf6146a3ce02dd558e8a9061d0194 Mon Sep 17 00:00:00 2001 From: Evan Date: Wed, 13 Jan 2021 11:08:43 -0700 Subject: [PATCH 21/36] fix double battle ai logic --- include/battle_ai_util.h | 3 + src/battle_ai_main.c | 561 +++++++++++++++++++++++---------------- src/battle_ai_util.c | 46 +++- 3 files changed, 379 insertions(+), 231 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 2aae8a61a6..4c2e14f7f2 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -105,6 +105,8 @@ bool32 ShouldSetSun(u8 battlerAtk, u16 atkAbility, u16 holdEffect); bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef); bool32 IsHealingMoveEffect(u16 effect); bool32 HasHealingEffect(u32 battler); +bool32 IsTrappingMoveEffect(u16 effect); +bool32 HasTrappingMoveEffect(u8 battler); bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move); bool32 IsThawingMove(u16 move); bool32 HasThawingMove(u8 battlerId); @@ -112,6 +114,7 @@ bool32 IsStatRaisingEffect(u16 effect); bool32 IsStatLoweringEffect(u16 effect); bool32 IsStatRaisingEffect(u16 effect); bool32 IsAttackBoostMoveEffect(u16 effect); +bool32 IsUngroundingEffect(u16 effect); // status checks bool32 CanBeBurned(u8 battler, u16 ability); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 2df626d2d7..cf51405813 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -57,7 +57,7 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = { @@ -68,7 +68,7 @@ static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = [4] = AI_Risky, // AI_FLAG_RISKY [5] = AI_PreferStrongestMove, // AI_FLAG_PREFER_STRONGEST_MOVE [6] = AI_PreferBatonPass, // AI_FLAG_PREFER_BATON_PASS - [7] = AI_TryOnAlly, // AI_FLAG_DOUBLE_BATTLE. + [7] = AI_DoubleBattle, // AI_FLAG_DOUBLE_BATTLE. [8] = AI_HPAware, // AI_FLAG_HP_AWARE [9] = NULL, // AI_FLAG_NEGATE_UNAWARE [10] = NULL, // AI_FLAG_WILL_SUICIDE @@ -484,7 +484,7 @@ static void BattleAI_DoAIProcessing(void) { // Call AI function AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = - sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId](gBattlerAttacker, + sBattleAiFuncTable[AI_THINKING_STRUCT->aiLogicId](sBattler_AI, gBattlerTarget, AI_THINKING_STRUCT->moveConsidered, AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex]); @@ -614,7 +614,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) RETURN_SCORE_MINUS(10); break; case ABILITY_MAGIC_BOUNCE: - if (TestMoveFlags(move, FLAG_MAGICCOAT_AFFECTED)) + if (TestMoveFlags(move, FLAG_MAGIC_COAT_AFFECTED)) RETURN_SCORE_MINUS(20); break; case ABILITY_CONTRARY: @@ -679,7 +679,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) RETURN_SCORE_MINUS(20); break; case ABILITY_MAGIC_BOUNCE: - if (TestMoveFlags(move, FLAG_MAGICCOAT_AFFECTED) && moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD)) + if (TestMoveFlags(move, FLAG_MAGIC_COAT_AFFECTED) && moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD)) RETURN_SCORE_MINUS(20); break; case ABILITY_SWEET_VEIL: @@ -1902,7 +1902,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; // no teammates to assist from break; case EFFECT_MAGIC_COAT: - if (!TestMoveFlagsInMoveset(battlerDef, FLAG_MAGICCOAT_AFFECTED)) + if (!TestMoveFlagsInMoveset(battlerDef, FLAG_MAGIC_COAT_AFFECTED)) score -= 10; break; case EFFECT_BELCH: @@ -2442,7 +2442,7 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // double battle logic -static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // move data u8 moveType = gBattleMoves[move].type; @@ -2453,249 +2453,354 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u16 atkPartnerAbility = AI_DATA->atkPartnerAbility; u16 atkPartnerHoldEffect = AI_DATA->atkPartnerHoldEffect; bool32 partnerProtecting = (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_PROTECT); - bool32 attackerHasBadAbility = (AI_DATA->atkAbility == ABILITY_TRUANT || AI_DATA->atkAbility == ABILITY_SLOW_START || AI_DATA->atkAbility == ABILITY_DEFEATIST); - bool32 partnerHasBadAbility = (atkPartnerAbility == ABILITY_TRUANT || atkPartnerAbility == ABILITY_SLOW_START || atkPartnerAbility == ABILITY_DEFEATIST); - - if (!IsBattlerAlive(battlerAtkPartner)) - return score; - - // partner ability checks - if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) - { - switch (atkPartnerAbility) - { - case ABILITY_VOLT_ABSORB: - if (!(AI_THINKING_STRUCT->aiFlags & 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(1); - break; - case ABILITY_LIGHTNING_ROD: - if (moveType == TYPE_ELECTRIC - && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) - && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) - RETURN_SCORE_PLUS(1); - break; - case ABILITY_WATER_ABSORB: - case ABILITY_DRY_SKIN: - if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HP_AWARE)) - RETURN_SCORE_MINUS(10); - break; // handled in AI_HPAware - case ABILITY_STORM_DRAIN: - if (moveType == TYPE_WATER - && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) - && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) - RETURN_SCORE_PLUS(1); - break; - case ABILITY_WATER_COMPACTION: - if (moveType == TYPE_WATER && GetMoveDamageResult(move) == MOVE_POWER_WEAK) - RETURN_SCORE_PLUS(1); // 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(1); - break; - case ABILITY_SAP_SIPPER: - if (moveType == TYPE_GRASS - && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) - && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) - RETURN_SCORE_PLUS(1); - break; - case ABILITY_JUSTIFIED: - if (moveType == TYPE_DARK - && !IS_MOVE_STATUS(move) - && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) - && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) - && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) - RETURN_SCORE_PLUS(1); - break; - case ABILITY_RATTLED: - if (!IS_MOVE_STATUS(move) - && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) - && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED) - && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) - RETURN_SCORE_PLUS(1); - break; - case ABILITY_CONTRARY: - if (IsStatLoweringEffect(effect)) - RETURN_SCORE_PLUS(2); - break; - case ABILITY_DEFIANT: - if (IsStatLoweringEffect(effect) - && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) - RETURN_SCORE_PLUS(1); - break; - case ABILITY_COMPETITIVE: - if (IsStatLoweringEffect(effect) - && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) - RETURN_SCORE_PLUS(1); - break; - } - } // ability checks - - // partner move effects - if (AI_DATA->partnerMove != MOVE_NONE) + bool32 attackerHasBadAbility = (GetAbilityRating(AI_DATA->atkAbility) < 0); + bool32 partnerHasBadAbility = (GetAbilityRating(atkPartnerAbility) < 0); + u16 predictedMove = gLastMoves[battlerDef]; //for now + + // check what effect partner is using + if (AI_DATA->partnerMove != 0) { switch (gBattleMoves[AI_DATA->partnerMove].effect) { + case EFFECT_HELPING_HAND: + if (IS_MOVE_STATUS(move)) + score += 5; + break; case EFFECT_PERISH_SONG: - if (!IsBattlerTrapped(battlerDef, TRUE) - && (gBattleMoves[move].effect == EFFECT_MEAN_LOOK - || gBattleMoves[move].effect == EFFECT_TRAP)) - RETURN_SCORE_PLUS(1); // target not trapped, but ally will trap them so perish song is good + if (!(gBattleMons[battlerDef].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED))) + { + if (IsTrappingMoveEffect(effect) || predictedMove == MOVE_INGRAIN) + score++; + } break; case EFFECT_ALWAYS_CRIT: - if (AI_DATA->atkAbility == ABILITY_ANGER_POINT // ai has anger point - && GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 1 // partner goes first - && CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) + // Ally decided to use Frost Breath on us. we must have Anger Point as our ability + if (AI_DATA->atkAbility == ABILITY_ANGER_POINT) { - // encourage multiple target moves - if (!IsAttackBoostMoveEffect(gBattleMoves[move].effect) - && !IS_MOVE_STATUS(move) - && gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) - RETURN_SCORE_PLUS(3); + if (GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 1) // partner moving first + { + // discourage raising our attack since it's about to be maxed out + if (IsAttackBoostMoveEffect(effect)) + score -= 3; + // encourage moves hitting multiple opponents + if (!IS_MOVE_STATUS(move) && (gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) + score += 3; + } } break; - } // partner move effects - } - - // attacker move effects - switch (gBattleMoves[move].effect) - { - case EFFECT_EVASION_UP: - if (move == MOVE_ACUPRESSURE && !partnerProtecting) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_PURIFY: - if (gBattleMons[battlerAtkPartner].status1 & STATUS1_ANY) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_SWAGGER: - if (gBattleMons[battlerAtkPartner].statStages[STAT_ATK] < MAX_STAT_STAGE - && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) - && (!CanBeConfused(battlerAtkPartner, TRUE) - || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION - || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_FLATTER: - if (gBattleMons[battlerAtkPartner].statStages[STAT_SPATK] < MAX_STAT_STAGE - && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) - && (!CanBeConfused(battlerAtkPartner, TRUE) - || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION - || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_SANDSTORM: - if (ShouldSetSandstorm(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_RAIN_DANCE: - if (ShouldSetRain(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_SUNNY_DAY: - if (ShouldSetSun(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_HAIL: - if (IsBattlerAlive(battlerAtkPartner) - && ShouldSetHail(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) - RETURN_SCORE_PLUS(2); - break; - case EFFECT_BEAT_UP: - if (atkPartnerAbility == ABILITY_JUSTIFIED - && moveType == TYPE_DARK - && !IS_MOVE_STATUS(move) - && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) - && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) - && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_HELPING_HAND: - if (AI_DATA->partnerMove != MOVE_NONE - && !partnerProtecting - && !IS_MOVE_STATUS(AI_DATA->partnerMove)) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_SKILL_SWAP: - if (!partnerProtecting && AI_DATA->atkAbility != AI_DATA->atkPartnerAbility && !attackerHasBadAbility) - { - if (AI_DATA->atkPartnerAbility == ABILITY_TRUANT) - { - RETURN_SCORE_PLUS(10); - } - else if (AI_DATA->atkAbility == ABILITY_COMPOUND_EYES - && HasMoveWithLowAccuracy(battlerAtkPartner, FOE(battlerAtkPartner), 90, TRUE, atkPartnerAbility, AI_GetAbility(FOE(battlerAtkPartner)), atkPartnerHoldEffect, AI_GetHoldEffect(FOE(battlerAtkPartner)))) - { - RETURN_SCORE_PLUS(3); - } - //else - //score -= 30; // we get there after breaking out } + } // check partner move effect + + + // consider our move effect relative to partner state + switch (effect) + { + case EFFECT_HELPING_HAND: + if (AI_DATA->partnerMove != 0 && !HasDamagingMove(battlerAtkPartner)) + score -= 5; break; - case EFFECT_ROLE_PLAY: - if (!partnerProtecting && attackerHasBadAbility && !partnerHasBadAbility) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_WORRY_SEED: - case EFFECT_GASTRO_ACID: - case EFFECT_SIMPLE_BEAM: - if (!partnerProtecting && partnerHasBadAbility) - RETURN_SCORE_PLUS(2); - break; - case EFFECT_ENTRAINMENT: - if (!partnerProtecting && partnerHasBadAbility && IsAbilityOfRating(AI_DATA->atkAbility, 0)) - RETURN_SCORE_PLUS(1); - break; - case EFFECT_SOAK: - if (!partnerProtecting && atkPartnerAbility == ABILITY_WONDER_GUARD - && (gBattleMons[battlerAtkPartner].type1 != TYPE_WATER - || gBattleMons[battlerAtkPartner].type2 != TYPE_WATER - || gBattleMons[battlerAtkPartner].type3 != TYPE_WATER)) - RETURN_SCORE_PLUS(1); + case EFFECT_PERISH_SONG: + if (AI_DATA->partnerMove != 0 && HasTrappingMoveEffect(battlerAtkPartner)) + score++; break; case EFFECT_MAGNET_RISE: if (IsBattlerGrounded(battlerAtk) && (HasMove(battlerAtkPartner, MOVE_EARTHQUAKE) || HasMove(battlerAtkPartner, MOVE_MAGNITUDE)) && (AI_GetMoveEffectiveness(MOVE_EARTHQUAKE) != AI_EFFECTIVENESS_x0)) // Doesn't resist ground move - RETURN_SCORE_PLUS(2); + { + RETURN_SCORE_PLUS(2); // partner has earthquake or magnitude -> good idea to use magnet rise + } break; - case EFFECT_INSTRUCT: + } // our effect relative to partner + + + // consider global move effects + switch (effect) + { + case EFFECT_SANDSTORM: + if (ShouldSetSandstorm(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(1); // our partner benefits from sandstorm + } + break; + case EFFECT_RAIN_DANCE: + if (ShouldSetRain(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(1); // our partner benefits from rain + } + break; + case EFFECT_SUNNY_DAY: + if (ShouldSetSun(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(1); // our partner benefits from sun + } + break; + case EFFECT_HAIL: + if (IsBattlerAlive(battlerAtkPartner) + && ShouldSetHail(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(2); // our partner benefits from hail + } + break; + } // global move effect check + + + // check specific target + if (IsTargetingPartner(battlerAtk, battlerDef)) + { + if (GetMoveDamageResult(move) == MOVE_POWER_DISCOURAGED) + { + // partner ability checks + if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) + { + switch (atkPartnerAbility) + { + case ABILITY_VOLT_ABSORB: + if (!(AI_THINKING_STRUCT->aiFlags & 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(1); + } + break; + case ABILITY_LIGHTNING_ROD: + if (moveType == TYPE_ELECTRIC + && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) + { + RETURN_SCORE_PLUS(1); + } + break; + case ABILITY_WATER_ABSORB: + case ABILITY_DRY_SKIN: + if (!(AI_THINKING_STRUCT->aiFlags & AI_FLAG_HP_AWARE)) + { + RETURN_SCORE_MINUS(10); + } + break; // handled in AI_HPAware + case ABILITY_STORM_DRAIN: + if (moveType == TYPE_WATER + && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) + { + RETURN_SCORE_PLUS(1); + } + break; + case ABILITY_WATER_COMPACTION: + if (moveType == TYPE_WATER && GetMoveDamageResult(move) == MOVE_POWER_WEAK) + { + RETURN_SCORE_PLUS(1); // 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(1); + } + break; + case ABILITY_SAP_SIPPER: + if (moveType == TYPE_GRASS + && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) + { + RETURN_SCORE_PLUS(1); + } + break; + case ABILITY_JUSTIFIED: + if (moveType == TYPE_DARK + && !IS_MOVE_STATUS(move) + && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) + && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) + { + RETURN_SCORE_PLUS(1); + } + break; + case ABILITY_RATTLED: + if (!IS_MOVE_STATUS(move) + && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED) + && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) + { + RETURN_SCORE_PLUS(1); + } + break; + case ABILITY_CONTRARY: + if (IsStatLoweringEffect(effect)) + { + RETURN_SCORE_PLUS(2); + } + break; + case ABILITY_DEFIANT: + if (IsStatLoweringEffect(effect) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)) + { + RETURN_SCORE_PLUS(1); + } + break; + case ABILITY_COMPETITIVE: + if (IsStatLoweringEffect(effect) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPATK)) + { + RETURN_SCORE_PLUS(1); + } + break; + } + } // ability checks + } // move power check + + // attacker move effects specifically targeting partner if (!partnerProtecting) { - u16 instructedMove; - if (GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 0) - instructedMove = AI_DATA->partnerMove; - else - instructedMove = gLastMoves[battlerAtkPartner]; - - if (instructedMove != MOVE_NONE - && !IS_MOVE_STATUS(instructedMove) - && gBattleMoves[instructedMove].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) //Use instruct on multi-target moves + switch (effect) { - RETURN_SCORE_PLUS(1); - } - } - break; - case EFFECT_AFTER_YOU: - if (GetWhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), TRUE) == 1 // opponent mon 1 goes before partner - || GetWhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), TRUE) == 1) // opponent mon 2 goes before partner - { - if (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_COUNTER || gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_MIRROR_COAT) - break; // These moves need to go last + case EFFECT_PURIFY: + if (gBattleMons[battlerAtkPartner].status1 & STATUS1_ANY) + { + RETURN_SCORE_PLUS(1); + } + break; + case EFFECT_SWAGGER: + if (gBattleMons[battlerAtkPartner].statStages[STAT_ATK] < MAX_STAT_STAGE + && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) + && (!CanBeConfused(battlerAtkPartner, TRUE) + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) + { + RETURN_SCORE_PLUS(1); + } + break; + case EFFECT_FLATTER: + if (gBattleMons[battlerAtkPartner].statStages[STAT_SPATK] < MAX_STAT_STAGE + && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) + && (!CanBeConfused(battlerAtkPartner, TRUE) + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION + || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) + { + RETURN_SCORE_PLUS(1); + } + break; + case EFFECT_BEAT_UP: + if (atkPartnerAbility == ABILITY_JUSTIFIED + && moveType == TYPE_DARK + && !IS_MOVE_STATUS(move) + && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) + && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) + && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) + { + RETURN_SCORE_PLUS(1); + } + break; + case EFFECT_SKILL_SWAP: + if (AI_DATA->atkAbility != AI_DATA->atkPartnerAbility && !attackerHasBadAbility) + { + if (AI_DATA->atkPartnerAbility == ABILITY_TRUANT) + { + RETURN_SCORE_PLUS(10); + } + else if (AI_DATA->atkAbility == ABILITY_COMPOUND_EYES + && HasMoveWithLowAccuracy(battlerAtkPartner, FOE(battlerAtkPartner), 90, TRUE, atkPartnerAbility, AI_GetAbility(FOE(battlerAtkPartner)), atkPartnerHoldEffect, AI_GetHoldEffect(FOE(battlerAtkPartner)))) + { + RETURN_SCORE_PLUS(3); + } + } + break; + case EFFECT_ROLE_PLAY: + if (attackerHasBadAbility && !partnerHasBadAbility) + { + RETURN_SCORE_PLUS(1); + } + break; + case EFFECT_WORRY_SEED: + case EFFECT_GASTRO_ACID: + case EFFECT_SIMPLE_BEAM: + if (partnerHasBadAbility) + { + RETURN_SCORE_PLUS(2); + } + break; + case EFFECT_ENTRAINMENT: + if (partnerHasBadAbility && IsAbilityOfRating(AI_DATA->atkAbility, 0)) + { + RETURN_SCORE_PLUS(1); + } + break; + case EFFECT_SOAK: + if (atkPartnerAbility == ABILITY_WONDER_GUARD + && (gBattleMons[battlerAtkPartner].type1 != TYPE_WATER + || gBattleMons[battlerAtkPartner].type2 != TYPE_WATER + || gBattleMons[battlerAtkPartner].type3 != TYPE_WATER)) + { + RETURN_SCORE_PLUS(1); + } + break; + case EFFECT_INSTRUCT: + { + u16 instructedMove; + if (GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 0) + instructedMove = AI_DATA->partnerMove; + else + instructedMove = gLastMoves[battlerAtkPartner]; - RETURN_SCORE_PLUS(1); - } - break; - } // attacker move effects + if (instructedMove != MOVE_NONE + && !IS_MOVE_STATUS(instructedMove) + && gBattleMoves[instructedMove].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) //Use instruct on multi-target moves + { + RETURN_SCORE_PLUS(1); + } + } + break; + case EFFECT_AFTER_YOU: + if (GetWhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), TRUE) == 1 // opponent mon 1 goes before partner + || GetWhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), TRUE) == 1) // opponent mon 2 goes before partner + { + if (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_COUNTER || gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_MIRROR_COAT) + break; // These moves need to go last + RETURN_SCORE_PLUS(1); + } + break; + } // attacker move effects + } // check partner protecting - RETURN_SCORE_MINUS(30); // otherwise, we do not want to target our ally + 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 (AI_DATA->atkAbility == ABILITY_TRUANT) + score += 5; + else if (IsAbilityOfRating(AI_DATA->atkAbility, 0) || IsAbilityOfRating(AI_DATA->defAbility, 10)) + score += 2; // we want to transfer our bad ability or take their awesome ability + break; + case EFFECT_EARTHQUAKE: + case EFFECT_MAGNITUDE: + if (!IsBattlerGrounded(battlerAtkPartner) + || (GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 1 && IsUngroundingEffect(gBattleMoves[AI_DATA->partnerMove].effect))) + score += 2; + 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)) + score -= 10; // partner will be hit by earthquake and is weak to it + else + score -= 3; + break; + } + + // lightning rod, flash fire against enemy handled in AI_CheckBadMove + } + + return score; } // AI_FLAG_CHECK_VIABILITY - a weird mix of increasing and decreasing scores diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 676091675e..afc02dfaa4 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1854,6 +1854,35 @@ bool32 HasHealingEffect(u32 battlerId) return FALSE; } +bool32 IsTrappingMoveEffect(u16 effect) +{ + switch (effect) + { + case EFFECT_MEAN_LOOK: + case EFFECT_TRAP: + case EFFECT_HIT_PREVENT_ESCAPE: + case EFFECT_FAIRY_LOCK: + //case EFFECT_NO_RETREAT: // TODO + return TRUE; + default: + return FALSE; + } +} + +bool32 HasTrappingMoveEffect(u8 battler) +{ + s32 i; + u16 *moves = GetMovesArray(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && IsTrappingMoveEffect(gBattleMoves[moves[i]].effect)) + return TRUE; + } + + return FALSE; +} + bool32 IsThawingMove(u16 move) { switch (move) @@ -1887,6 +1916,18 @@ bool32 HasThawingMove(u8 battlerId) return FALSE; } +bool32 IsUngroundingEffect(u16 effect) +{ + switch (effect) + { + case EFFECT_MAGNET_RISE: + return TRUE; + default: + return FALSE; + } +} + +// for anger point bool32 IsAttackBoostMoveEffect(u16 effect) { switch (effect) @@ -1899,6 +1940,7 @@ bool32 IsAttackBoostMoveEffect(u16 effect) case EFFECT_COIL: case EFFECT_BELLY_DRUM: case EFFECT_BULK_UP: + case EFFECT_GROWTH: return TRUE; default: return FALSE; @@ -2884,9 +2926,6 @@ u16 GetAllyChosenMove(void) bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef) { - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - return FALSE; - if ((battlerAtk & BIT_SIDE) == (battlerDef & BIT_SIDE)) return TRUE; @@ -3196,6 +3235,7 @@ bool32 IsAbilityOfRating(u16 ability, s8 rating) { if (sAiAbilityRatings[ability] >= rating) return TRUE; + return FALSE; } s8 GetAbilityRating(u16 ability) From 062d2ee50eba8896177fc55847518bd3cf6d4dc0 Mon Sep 17 00:00:00 2001 From: Evan Date: Wed, 13 Jan 2021 16:42:10 -0700 Subject: [PATCH 22/36] add atk up 3 effects to HpAware --- src/battle_ai_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index cf51405813..ebadc0ac71 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -4880,6 +4880,8 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_BULK_UP: case EFFECT_CALM_MIND: case EFFECT_DRAGON_DANCE: + case EFFECT_DEFENSE_UP_3: + case EFFECT_SPECIAL_ATTACK_UP_3: score -= 2; break; default: From 44a124acb7b7bbafb89a25658b0a72b5ce819fce Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 15 Jan 2021 09:23:23 -0700 Subject: [PATCH 23/36] fix CanBeParayzed --- src/battle_ai_util.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index afc02dfaa4..a55f65a54b 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -2599,12 +2599,12 @@ bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 return TRUE; } -static bool32 CanBeParayzed(battlerDef, defAbility) +static bool32 CanBeParayzed(u8 battler, u16 ability) { - if (defAbility == ABILITY_LIMBER - || IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC) - || gBattleMons[battlerDef].status1 & STATUS1_ANY - || IsAbilityStatusProtected(battlerDef)) + if (ability == ABILITY_LIMBER + || IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC) + || gBattleMons[battler].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battler)) return FALSE; return TRUE; } From 24b19eb9a43be5fa16c053134ace1c66529edf20 Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 15 Jan 2021 21:29:39 -0700 Subject: [PATCH 24/36] fix AI_WeatherHasEffect --- src/battle_ai_util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index a55f65a54b..28d921a06e 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1130,16 +1130,16 @@ bool32 AI_WeatherHasEffect(void) { u32 i; if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) - return FALSE; // AI doesn't understand weather supression (handicap) + return TRUE; // AI doesn't understand weather supression (handicap) // need to manually check since we don't necessarily know opponent ability for (i = 0; i < gBattlersCount; i++) { if (IsBattlerAlive(i) && (AI_GetAbility(i) == ABILITY_AIR_LOCK || AI_GetAbility(i) == ABILITY_CLOUD_NINE)) - return TRUE; + return FALSE; } - return FALSE; + return TRUE; } bool32 IsAromaVeilProtectedMove(u16 move) From 71185dbf677efe85a74753e863f016710e841a33 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 19 Jan 2021 08:50:36 -0700 Subject: [PATCH 25/36] fix DoesBattlerIgnoreAbilityChecks --- src/battle_ai_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index ebadc0ac71..c8de807360 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -551,7 +551,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; // target ability checks - if (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) + if (!DoesBattlerIgnoreAbilityChecks(AI_DATA->battlerAtk, move)) { switch (AI_DATA->defAbility) { @@ -1630,11 +1630,11 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_TEETER_DANCE: if (((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) - || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && AI_DATA->defAbility == ABILITY_OWN_TEMPO) + || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->battlerAtk, move) && AI_DATA->defAbility == ABILITY_OWN_TEMPO) || (IsBattlerGrounded(battlerDef) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) || (DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) && ((gBattleMons[AI_DATA->battlerDefPartner].status2 & STATUS2_CONFUSION) - || (!DoesBattlerIgnoreAbilityChecks(battlerAtk, move) && AI_DATA->defPartnerAbility == ABILITY_OWN_TEMPO) + || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->battlerAtk, move) && AI_DATA->defPartnerAbility == ABILITY_OWN_TEMPO) || (IsBattlerGrounded(AI_DATA->battlerDefPartner) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) || (DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, move)))) { @@ -2551,7 +2551,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (GetMoveDamageResult(move) == MOVE_POWER_DISCOURAGED) { // partner ability checks - if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(battlerAtk, move)) + if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(AI_DATA->battlerAtk, move)) { switch (atkPartnerAbility) { From 455899acf7f6933fddacd09f70c0ce40791ef1bb Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 19 Jan 2021 08:54:39 -0700 Subject: [PATCH 26/36] fix AI_DATA->battlerAtk --- src/battle_ai_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index c8de807360..efa5cfc2b8 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -551,7 +551,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; // target ability checks - if (!DoesBattlerIgnoreAbilityChecks(AI_DATA->battlerAtk, move)) + if (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) { switch (AI_DATA->defAbility) { @@ -1630,11 +1630,11 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_TEETER_DANCE: if (((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) - || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->battlerAtk, move) && AI_DATA->defAbility == ABILITY_OWN_TEMPO) + || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move) && AI_DATA->defAbility == ABILITY_OWN_TEMPO) || (IsBattlerGrounded(battlerDef) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) || (DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) && ((gBattleMons[AI_DATA->battlerDefPartner].status2 & STATUS2_CONFUSION) - || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->battlerAtk, move) && AI_DATA->defPartnerAbility == ABILITY_OWN_TEMPO) + || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move) && AI_DATA->defPartnerAbility == ABILITY_OWN_TEMPO) || (IsBattlerGrounded(AI_DATA->battlerDefPartner) && (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) || (DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, move)))) { @@ -2551,7 +2551,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (GetMoveDamageResult(move) == MOVE_POWER_DISCOURAGED) { // partner ability checks - if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(AI_DATA->battlerAtk, move)) + if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) { switch (atkPartnerAbility) { From 6b59a9ac01181302bd9e08b79db42b528c3bcaf7 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 19 Jan 2021 12:58:58 -0700 Subject: [PATCH 27/36] add ai info debug option --- include/battle.h | 4 +- src/battle_ai_util.c | 2 + src/battle_debug.c | 408 +++++++++++++++++++++++++++++++++++++++++++ src/battle_main.c | 2 + 4 files changed, 414 insertions(+), 2 deletions(-) diff --git a/include/battle.h b/include/battle.h index b38513a672..608ed8b4b7 100644 --- a/include/battle.h +++ b/include/battle.h @@ -263,7 +263,7 @@ struct AiLogicData struct AI_ThinkingStruct { - struct AiLogicData *data; + struct AiLogicData data; u8 aiState; u8 movesetIndex; u16 moveConsidered; @@ -321,7 +321,7 @@ struct BattleResources }; #define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) -#define AI_DATA ((struct AiLogicData *)(gBattleResources->ai->data)) +#define AI_DATA ((struct AiLogicData *)(&gBattleResources->ai->data)) #define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) struct BattleResults diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 28d921a06e..a580060dcf 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1076,6 +1076,8 @@ u16 AI_GetHoldEffect(u32 battlerId) return HOLD_EFFECT_NONE; if (AI_GetAbility(battlerId) == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) return HOLD_EFFECT_NONE; + + return holdEffect; } // different from IsBattlerGrounded in that we don't always know battler's hold effect or ability diff --git a/src/battle_debug.c b/src/battle_debug.c index bc17cafb3a..8f5b5e365b 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -33,6 +33,7 @@ #include "constants/moves.h" #include "constants/items.h" #include "constants/rgb.h" +#include "constants/hold_effects.h" #define MAX_MODIFY_DIGITS 4 @@ -99,6 +100,7 @@ enum LIST_ITEM_SIDE_STATUS, LIST_ITEM_AI, LIST_ITEM_AI_MOVES_PTS, + LIST_ITEM_AI_INFO, LIST_ITEM_VARIOUS, LIST_ITEM_COUNT }; @@ -150,7 +152,11 @@ enum VARIOUS_IN_LOVE, }; +// Static Declarations +static const u8 *GetHoldEffectName(u16 holdEffect); + // const rom data +static const u8 sText_HoldEffect[] = _("Hold Effect"); static const u8 sText_Ability[] = _("Ability"); static const u8 sText_Moves[] = _("Moves"); static const u8 sText_Stats[] = _("Stats"); @@ -223,6 +229,7 @@ static const u8 sText_HpAware[] = _("HP aware"); static const u8 sText_Unknown[] = _("Unknown"); static const u8 sText_InLove[] = _("In Love"); static const u8 sText_AIMovePts[] = _("AI Move Pts"); +static const u8 sText_AiKnowledge[] = _("AI Info"); static const u8 sText_EffectOverride[] = _("Effect Override"); static const u8 sText_EmptyString[] = _(""); @@ -320,6 +327,7 @@ static const struct ListMenuItem sMainListItems[] = {sText_SideStatus, LIST_ITEM_SIDE_STATUS}, {sText_AI, LIST_ITEM_AI}, {sText_AIMovePts, LIST_ITEM_AI_MOVES_PTS}, + {sText_AiKnowledge, LIST_ITEM_AI_INFO}, {sText_Various, LIST_ITEM_VARIOUS}, }; @@ -784,6 +792,114 @@ static void SwitchToAiPointsView(u8 taskId) GetStructPtr(taskId)->aiViewState = 0; } +static const u8 *const sAiInfoItemNames[] = +{ + sText_Ability, + sText_HeldItem, + sText_HoldEffect, +}; +static void PutAiInfoText(struct BattleDebugMenu *data) +{ + u32 i, j, count; + u8 *text = malloc(0x50); + + FillWindowPixelBuffer(data->aiMovesWindowId, 0x11); + + // item names + for (i = 0; i < ARRAY_COUNT(sAiInfoItemNames); i++) + { + AddTextPrinterParameterized(data->aiMovesWindowId, 1, sAiInfoItemNames[i], 3, i * 15, 0, NULL); + } + + // items info + for (i = 0; i < gBattlersCount; i++) + { + if (GET_BATTLER_SIDE(i) == B_SIDE_PLAYER && IsBattlerAlive(i)) + { + u16 ability = AI_GetAbility(i); + u16 holdEffect = AI_GetHoldEffect(i); + u16 item = gBattleMons[i].item; + u8 x = (i == B_POSITION_PLAYER_LEFT) ? 83 + (i) * 75 : 83 + (i-1) * 75; + AddTextPrinterParameterized(data->aiMovesWindowId, 0, gAbilityNames[ability], x, 0, 0, NULL); + AddTextPrinterParameterized(data->aiMovesWindowId, 0, ItemId_GetName(item), x, 15, 0, NULL); + AddTextPrinterParameterized(data->aiMovesWindowId, 0, GetHoldEffectName(holdEffect), x, 30, 0, NULL); + } + } + + CopyWindowToVram(data->aiMovesWindowId, 3); + free(text); +} + +static void Task_ShowAiKnowledge(u8 taskId) +{ + u32 i, count; + struct WindowTemplate winTemplate; + struct BattleDebugMenu *data = GetStructPtr(taskId); + + switch (data->aiViewState) + { + case 0: + HideBg(0); + ShowBg(1); + + // Swap battler if it's player mon + data->aiBattlerId = data->battlerId; + while (!IsBattlerAIControlled(data->aiBattlerId)) + { + if (++data->aiBattlerId >= gBattlersCount) + data->aiBattlerId = 0; + } + + LoadMonIconPalettes(); + for (count = 0, i = 0; i < MAX_BATTLERS_COUNT; i++) + { + if (GET_BATTLER_SIDE(i) == B_SIDE_PLAYER && IsBattlerAlive(i)) + { + data->aiIconSpriteIds[i] = CreateMonIcon(gBattleMons[i].species, + SpriteCallbackDummy, + 95 + (count * 80), 17, 0, 0, FALSE); + gSprites[data->aiIconSpriteIds[i]].data[0] = i; // battler id + count++; + } + else + { + data->aiIconSpriteIds[i] = 0xFF; + } + } + data->aiMonSpriteId = CreateMonPicSprite_HandleDeoxys(gBattleMons[data->aiBattlerId].species, + gBattleMons[data->aiBattlerId].otId, + gBattleMons[data->aiBattlerId].personality, + TRUE, + 39, 130, 15, 0xFFFF); + data->aiViewState++; + break; + // Put text + case 1: + winTemplate = CreateWindowTemplate(1, 0, 4, 27, 14, 15, 0x200); + data->aiMovesWindowId = AddWindow(&winTemplate); + PutWindowTilemap(data->aiMovesWindowId); + PutAiInfoText(data); + data->aiViewState++; + break; + // Input + case 2: + if (gMain.newKeys & (SELECT_BUTTON | B_BUTTON)) + { + SwitchToDebugView(taskId); + HideBg(1); + ShowBg(0); + return; + } + break; + } +} + +static void SwitchToAiInfoView(u8 taskId) +{ + gTasks[taskId].func = Task_ShowAiKnowledge; + GetStructPtr(taskId)->aiViewState = 0; +} + static void SwitchToDebugView(u8 taskId) { u32 i; @@ -845,6 +961,11 @@ static void Task_DebugMenuProcessInput(u8 taskId) SwitchToAiPointsView(taskId); return; } + else if (listItemId == LIST_ITEM_AI_INFO && gMain.newKeys & A_BUTTON) + { + SwitchToAiInfoView(taskId); + return; + } data->currentMainListItemId = listItemId; // Create the secondary menu list. @@ -1041,6 +1162,7 @@ static void CreateSecondaryListMenu(struct BattleDebugMenu *data) itemsCount = ARRAY_COUNT(sSideStatusListItems); break; case LIST_ITEM_AI_MOVES_PTS: + case LIST_ITEM_AI_INFO: return; } @@ -1678,3 +1800,289 @@ static void UpdateMonData(struct BattleDebugMenu *data) } } } + +static const u8 sText_HoldEffectNone[] = _("????????"); +static const u8 sText_HoldEffectRestoreHp[] = _("Restore Hp"); +static const u8 sText_HoldEffectCurePar[] = _("Cure Par"); +static const u8 sText_HoldEffectCureSlp[] = _("Cure Slp"); +static const u8 sText_HoldEffectCurePsn[] = _("Cure Psn"); +static const u8 sText_HoldEffectCureBrn[] = _("Cure Brn"); +static const u8 sText_HoldEffectCureFrz[] = _("Cure Frz"); +static const u8 sText_HoldEffectRestorePp[] = _("Restore Pp"); +static const u8 sText_HoldEffectCureConfusion[] = _("Cure Confusion"); +static const u8 sText_HoldEffectCureStatus[] = _("Cure Status"); +static const u8 sText_HoldEffectConfuseSpicy[] = _("Confuse Spicy"); +static const u8 sText_HoldEffectConfuseDry[] = _("Confuse Dry"); +static const u8 sText_HoldEffectConfuseSweet[] = _("Confuse Sweet"); +static const u8 sText_HoldEffectConfuseBitter[] = _("Confuse Bitter"); +static const u8 sText_HoldEffectConfuseSour[] = _("Confuse Sour"); +static const u8 sText_HoldEffectAttackUp[] = _("Attack Up"); +static const u8 sText_HoldEffectDefenseUp[] = _("Defense Up"); +static const u8 sText_HoldEffectSpeedUp[] = _("Speed Up"); +static const u8 sText_HoldEffectSpAttackUp[] = _("Sp Attack Up"); +static const u8 sText_HoldEffectSpDefenseUp[] = _("Sp Defense Up"); +static const u8 sText_HoldEffectCriticalUp[] = _("Critical Up"); +static const u8 sText_HoldEffectRandomStatUp[] = _("Random Stat Up"); +static const u8 sText_HoldEffectEvasionUp[] = _("Evasion Up"); +static const u8 sText_HoldEffectRestoreStats[] = _("Restore Stats"); +static const u8 sText_HoldEffectMachoBrace[] = _("Macho Brace"); +static const u8 sText_HoldEffectExpShare[] = _("Exp Share"); +static const u8 sText_HoldEffectQuickClaw[] = _("Quick Claw"); +static const u8 sText_HoldEffectHappinessUp[] = _("Happiness Up"); +static const u8 sText_HoldEffectMentalHerb[] = _("Mental Herb"); +static const u8 sText_HoldEffectChoiceBand[] = _("Choice Band"); +static const u8 sText_HoldEffectFlinch[] = _("Flinch"); +static const u8 sText_HoldEffectBugPower[] = _("Bug Power"); +static const u8 sText_HoldEffectDoublePrize[] = _("Double Prize"); +static const u8 sText_HoldEffectRepel[] = _("Repel"); +static const u8 sText_HoldEffectSoulDew[] = _("Soul Dew"); +static const u8 sText_HoldEffectDeepSeaTooth[] = _("Deep Sea Tooth"); +static const u8 sText_HoldEffectDeepSeaScale[] = _("Deep Sea Scale"); +static const u8 sText_HoldEffectCanAlwaysRun[] = _("Can Always Run"); +static const u8 sText_HoldEffectPreventEvolve[] = _("Prevent Evolve"); +static const u8 sText_HoldEffectFocusBand[] = _("Focus Band"); +static const u8 sText_HoldEffectLuckyEgg[] = _("Lucky Egg"); +static const u8 sText_HoldEffectScopeLens[] = _("Scope Lens"); +static const u8 sText_HoldEffectSteelPower[] = _("Steel Power"); +static const u8 sText_HoldEffectLeftovers[] = _("Leftovers"); +static const u8 sText_HoldEffectDragonScale[] = _("Dragon Scale"); +static const u8 sText_HoldEffectLightBall[] = _("Light Ball"); +static const u8 sText_HoldEffectGroundPower[] = _("Ground Power"); +static const u8 sText_HoldEffectRockPower[] = _("Rock Power"); +static const u8 sText_HoldEffectGrassPower[] = _("Grass Power"); +static const u8 sText_HoldEffectDarkPower[] = _("Dark Power"); +static const u8 sText_HoldEffectFightingPower[] = _("Fighting Power"); +static const u8 sText_HoldEffectElectricPower[] = _("Electric Power"); +static const u8 sText_HoldEffectWaterPower[] = _("Water Power"); +static const u8 sText_HoldEffectFlyingPower[] = _("Flying Power"); +static const u8 sText_HoldEffectPoisonPower[] = _("Poison Power"); +static const u8 sText_HoldEffectIcePower[] = _("Ice Power"); +static const u8 sText_HoldEffectGhostPower[] = _("Ghost Power"); +static const u8 sText_HoldEffectPsychicPower[] = _("Psychic Power"); +static const u8 sText_HoldEffectFirePower[] = _("Fire Power"); +static const u8 sText_HoldEffectDragonPower[] = _("Dragon Power"); +static const u8 sText_HoldEffectNormalPower[] = _("Normal Power"); +static const u8 sText_HoldEffectUpGrade[] = _("Up Grade"); +static const u8 sText_HoldEffectShellBell[] = _("Shell Bell"); +static const u8 sText_HoldEffectLuckyPunch[] = _("Lucky Punch"); +static const u8 sText_HoldEffectMetalPowder[] = _("Metal Powder"); +static const u8 sText_HoldEffectThickClub[] = _("Thick Club"); +static const u8 sText_HoldEffectStick[] = _("Stick"); +static const u8 sText_HoldEffectChoiceScarf[] = _("Choice Scarf"); +static const u8 sText_HoldEffectChoiceSpecs[] = _("Choice Specs"); +static const u8 sText_HoldEffectDampRock[] = _("Damp Rock"); +static const u8 sText_HoldEffectGripClaw[] = _("Grip Claw"); +static const u8 sText_HoldEffectHeatRock[] = _("Heat Rock"); +static const u8 sText_HoldEffectIcyRock[] = _("Icy Rock"); +static const u8 sText_HoldEffectLightClay[] = _("Light Clay"); +static const u8 sText_HoldEffectSmoothRock[] = _("Smooth Rock"); +static const u8 sText_HoldEffectPowerHerb[] = _("Power Herb"); +static const u8 sText_HoldEffectBigRoot[] = _("Big Root"); +static const u8 sText_HoldEffectExpertBelt[] = _("Expert Belt"); +static const u8 sText_HoldEffectLifeOrb[] = _("Life Orb"); +static const u8 sText_HoldEffectMetronome[] = _("Metronome"); +static const u8 sText_HoldEffectMuscleBand[] = _("Muscle Band"); +static const u8 sText_HoldEffectWideLens[] = _("Wide Lens"); +static const u8 sText_HoldEffectWiseGlasses[] = _("Wise Glasses"); +static const u8 sText_HoldEffectZoomLens[] = _("Zoom Lens"); +static const u8 sText_HoldEffectLaggingTail[] = _("Lagging Tail"); +static const u8 sText_HoldEffectFocusSash[] = _("Focus Sash"); +static const u8 sText_HoldEffectFlameOrb[] = _("Flame Orb"); +static const u8 sText_HoldEffectToxicOrb[] = _("Toxic Orb"); +static const u8 sText_HoldEffectStickyBarb[] = _("Sticky Barb"); +static const u8 sText_HoldEffectIronBall[] = _("Iron Ball"); +static const u8 sText_HoldEffectBlackSludge[] = _("Black Sludge"); +static const u8 sText_HoldEffectDestinyKnot[] = _("Destiny Knot"); +static const u8 sText_HoldEffectShedShell[] = _("Shed Shell"); +static const u8 sText_HoldEffectQuickPowder[] = _("Quick Powder"); +static const u8 sText_HoldEffectAdamantOrb[] = _("Adamant Orb"); +static const u8 sText_HoldEffectLustrousOrb[] = _("Lustrous Orb"); +static const u8 sText_HoldEffectGriseousOrb[] = _("Griseous Orb"); +static const u8 sText_HoldEffectGracidea[] = _("Gracidea"); +static const u8 sText_HoldEffectResistBerry[] = _("Resist Berry"); +static const u8 sText_HoldEffectPowerItem[] = _("Power Item"); +static const u8 sText_HoldEffectRestorePctHp[] = _("Restore Pct Hp"); +static const u8 sText_HoldEffectMicleBerry[] = _("Micle Berry"); +static const u8 sText_HoldEffectCustapBerry[] = _("Custap Berry"); +static const u8 sText_HoldEffectJabocaBerry[] = _("Jaboca Berry"); +static const u8 sText_HoldEffectRowapBerry[] = _("Rowap Berry"); +static const u8 sText_HoldEffectKeeBerry[] = _("Kee Berry"); +static const u8 sText_HoldEffectMarangaBerry[] = _("Maranga Berry"); +static const u8 sText_HoldEffectFloatStone[] = _("Float Stone"); +static const u8 sText_HoldEffectEviolite[] = _("Eviolite"); +static const u8 sText_HoldEffectAssaultVest[] = _("Assault Vest"); +static const u8 sText_HoldEffectDrive[] = _("Drive"); +static const u8 sText_HoldEffectGems[] = _("Gems"); +static const u8 sText_HoldEffectRockyHelmet[] = _("Rocky Helmet"); +static const u8 sText_HoldEffectAirBalloon[] = _("Air Balloon"); +static const u8 sText_HoldEffectRedCard[] = _("Red Card"); +static const u8 sText_HoldEffectRingTarget[] = _("Ring Target"); +static const u8 sText_HoldEffectBindingBand[] = _("Binding Band"); +static const u8 sText_HoldEffectEjectButton[] = _("Eject Button"); +static const u8 sText_HoldEffectAbsorbBulb[] = _("Absorb Bulb"); +static const u8 sText_HoldEffectCellBattery[] = _("Cell Battery"); +static const u8 sText_HoldEffectFairyPower[] = _("Fairy Power"); +static const u8 sText_HoldEffectMegaStone[] = _("Mega Stone"); +static const u8 sText_HoldEffectSafetyGoogles[] = _("Safety Googles"); +static const u8 sText_HoldEffectLuminousMoss[] = _("Luminous Moss"); +static const u8 sText_HoldEffectSnowball[] = _("Snowball"); +static const u8 sText_HoldEffectWeaknessPolicy[] = _("Weakness Policy"); +static const u8 sText_HoldEffectProtectivePads[] = _("Protective Pads"); +static const u8 sText_HoldEffectTerrainExtender[] = _("Terrain Extender"); +static const u8 sText_HoldEffectSeeds[] = _("Seeds"); +static const u8 sText_HoldEffectAdrenalineOrb[] = _("Adrenaline Orb"); +static const u8 sText_HoldEffectMemory[] = _("Memory"); +static const u8 sText_HoldEffectPlate[] = _("Plate"); +static const u8 sText_HoldEffectUtilityUmbrella[] = _("Utility Umbrella"); +static const u8 sText_HoldEffectEjectPack[] = _("Eject Pack"); +static const u8 sText_HoldEffectRoomService[] = _("Room Service"); +static const u8 sText_HoldEffectBlunderPolicy[] = _("Blunder Policy"); +static const u8 sText_HoldEffectHeavyDutyBoots[] = _("Heavy Duty Boots"); +static const u8 sText_HoldEffectThroatSpray[] = _("Throat Spray"); +static const u8 *const sHoldEffectNames[] = +{ + [HOLD_EFFECT_NONE] = sText_HoldEffectNone, + [HOLD_EFFECT_RESTORE_HP] = sText_HoldEffectRestoreHp, + [HOLD_EFFECT_CURE_PAR] = sText_HoldEffectCurePar, + [HOLD_EFFECT_CURE_SLP] = sText_HoldEffectCureSlp, + [HOLD_EFFECT_CURE_PSN] = sText_HoldEffectCurePsn, + [HOLD_EFFECT_CURE_BRN] = sText_HoldEffectCureBrn, + [HOLD_EFFECT_CURE_FRZ] = sText_HoldEffectCureFrz, + [HOLD_EFFECT_RESTORE_PP] = sText_HoldEffectRestorePp, + [HOLD_EFFECT_CURE_CONFUSION] = sText_HoldEffectCureConfusion, + [HOLD_EFFECT_CURE_STATUS] = sText_HoldEffectCureStatus, + [HOLD_EFFECT_CONFUSE_SPICY] = sText_HoldEffectConfuseSpicy, + [HOLD_EFFECT_CONFUSE_DRY] = sText_HoldEffectConfuseDry, + [HOLD_EFFECT_CONFUSE_SWEET] = sText_HoldEffectConfuseSweet, + [HOLD_EFFECT_CONFUSE_BITTER] = sText_HoldEffectConfuseBitter, + [HOLD_EFFECT_CONFUSE_SOUR] = sText_HoldEffectConfuseSour, + [HOLD_EFFECT_ATTACK_UP] = sText_HoldEffectAttackUp, + [HOLD_EFFECT_DEFENSE_UP] = sText_HoldEffectDefenseUp, + [HOLD_EFFECT_SPEED_UP] = sText_HoldEffectSpeedUp, + [HOLD_EFFECT_SP_ATTACK_UP] = sText_HoldEffectSpAttackUp, + [HOLD_EFFECT_SP_DEFENSE_UP] = sText_HoldEffectSpDefenseUp, + [HOLD_EFFECT_CRITICAL_UP] = sText_HoldEffectCriticalUp, + [HOLD_EFFECT_RANDOM_STAT_UP] = sText_HoldEffectRandomStatUp, + [HOLD_EFFECT_EVASION_UP] = sText_HoldEffectEvasionUp, + [HOLD_EFFECT_RESTORE_STATS] = sText_HoldEffectRestoreStats, + [HOLD_EFFECT_MACHO_BRACE] = sText_HoldEffectMachoBrace, + [HOLD_EFFECT_EXP_SHARE] = sText_HoldEffectExpShare, + [HOLD_EFFECT_QUICK_CLAW] = sText_HoldEffectQuickClaw, + [HOLD_EFFECT_HAPPINESS_UP] = sText_HoldEffectHappinessUp, + //[HOLD_EFFECT_MENTAL_HERB] = sText_HoldEffectMentalHerb, + [HOLD_EFFECT_CHOICE_BAND] = sText_HoldEffectChoiceBand, + [HOLD_EFFECT_FLINCH] = sText_HoldEffectFlinch, + [HOLD_EFFECT_BUG_POWER] = sText_HoldEffectBugPower, + [HOLD_EFFECT_DOUBLE_PRIZE] = sText_HoldEffectDoublePrize, + [HOLD_EFFECT_REPEL] = sText_HoldEffectRepel, + [HOLD_EFFECT_SOUL_DEW] = sText_HoldEffectSoulDew, + [HOLD_EFFECT_DEEP_SEA_TOOTH] = sText_HoldEffectDeepSeaTooth, + [HOLD_EFFECT_DEEP_SEA_SCALE] = sText_HoldEffectDeepSeaScale, + [HOLD_EFFECT_CAN_ALWAYS_RUN] = sText_HoldEffectCanAlwaysRun, + [HOLD_EFFECT_PREVENT_EVOLVE] = sText_HoldEffectPreventEvolve, + [HOLD_EFFECT_FOCUS_BAND] = sText_HoldEffectFocusBand, + [HOLD_EFFECT_LUCKY_EGG] = sText_HoldEffectLuckyEgg, + [HOLD_EFFECT_SCOPE_LENS] = sText_HoldEffectScopeLens, + [HOLD_EFFECT_STEEL_POWER] = sText_HoldEffectSteelPower, + [HOLD_EFFECT_LEFTOVERS] = sText_HoldEffectLeftovers, + [HOLD_EFFECT_DRAGON_SCALE] = sText_HoldEffectDragonScale, + [HOLD_EFFECT_LIGHT_BALL] = sText_HoldEffectLightBall, + [HOLD_EFFECT_GROUND_POWER] = sText_HoldEffectGroundPower, + [HOLD_EFFECT_ROCK_POWER] = sText_HoldEffectRockPower, + [HOLD_EFFECT_GRASS_POWER] = sText_HoldEffectGrassPower, + [HOLD_EFFECT_DARK_POWER] = sText_HoldEffectDarkPower, + [HOLD_EFFECT_FIGHTING_POWER] = sText_HoldEffectFightingPower, + [HOLD_EFFECT_ELECTRIC_POWER] = sText_HoldEffectElectricPower, + [HOLD_EFFECT_WATER_POWER] = sText_HoldEffectWaterPower, + [HOLD_EFFECT_FLYING_POWER] = sText_HoldEffectFlyingPower, + [HOLD_EFFECT_POISON_POWER] = sText_HoldEffectPoisonPower, + [HOLD_EFFECT_ICE_POWER] = sText_HoldEffectIcePower, + [HOLD_EFFECT_GHOST_POWER] = sText_HoldEffectGhostPower, + [HOLD_EFFECT_PSYCHIC_POWER] = sText_HoldEffectPsychicPower, + [HOLD_EFFECT_FIRE_POWER] = sText_HoldEffectFirePower, + [HOLD_EFFECT_DRAGON_POWER] = sText_HoldEffectDragonPower, + [HOLD_EFFECT_NORMAL_POWER] = sText_HoldEffectNormalPower, + [HOLD_EFFECT_UP_GRADE] = sText_HoldEffectUpGrade, + [HOLD_EFFECT_SHELL_BELL] = sText_HoldEffectShellBell, + [HOLD_EFFECT_LUCKY_PUNCH] = sText_HoldEffectLuckyPunch, + [HOLD_EFFECT_METAL_POWDER] = sText_HoldEffectMetalPowder, + [HOLD_EFFECT_THICK_CLUB] = sText_HoldEffectThickClub, + [HOLD_EFFECT_STICK] = sText_HoldEffectStick, + [HOLD_EFFECT_CHOICE_SCARF] = sText_HoldEffectChoiceScarf, + [HOLD_EFFECT_CHOICE_SPECS] = sText_HoldEffectChoiceSpecs, + [HOLD_EFFECT_DAMP_ROCK] = sText_HoldEffectDampRock, + [HOLD_EFFECT_GRIP_CLAW] = sText_HoldEffectGripClaw, + [HOLD_EFFECT_HEAT_ROCK] = sText_HoldEffectHeatRock, + [HOLD_EFFECT_ICY_ROCK] = sText_HoldEffectIcyRock, + [HOLD_EFFECT_LIGHT_CLAY] = sText_HoldEffectLightClay, + [HOLD_EFFECT_SMOOTH_ROCK] = sText_HoldEffectSmoothRock, + [HOLD_EFFECT_POWER_HERB] = sText_HoldEffectPowerHerb, + [HOLD_EFFECT_BIG_ROOT] = sText_HoldEffectBigRoot, + [HOLD_EFFECT_EXPERT_BELT] = sText_HoldEffectExpertBelt, + [HOLD_EFFECT_LIFE_ORB] = sText_HoldEffectLifeOrb, + [HOLD_EFFECT_METRONOME] = sText_HoldEffectMetronome, + [HOLD_EFFECT_MUSCLE_BAND] = sText_HoldEffectMuscleBand, + [HOLD_EFFECT_WIDE_LENS] = sText_HoldEffectWideLens, + [HOLD_EFFECT_WISE_GLASSES] = sText_HoldEffectWiseGlasses, + [HOLD_EFFECT_ZOOM_LENS] = sText_HoldEffectZoomLens, + [HOLD_EFFECT_LAGGING_TAIL] = sText_HoldEffectLaggingTail, + [HOLD_EFFECT_FOCUS_SASH] = sText_HoldEffectFocusSash, + [HOLD_EFFECT_FLAME_ORB] = sText_HoldEffectFlameOrb, + [HOLD_EFFECT_TOXIC_ORB] = sText_HoldEffectToxicOrb, + [HOLD_EFFECT_STICKY_BARB] = sText_HoldEffectStickyBarb, + [HOLD_EFFECT_IRON_BALL] = sText_HoldEffectIronBall, + [HOLD_EFFECT_BLACK_SLUDGE] = sText_HoldEffectBlackSludge, + [HOLD_EFFECT_DESTINY_KNOT] = sText_HoldEffectDestinyKnot, + [HOLD_EFFECT_SHED_SHELL] = sText_HoldEffectShedShell, + [HOLD_EFFECT_QUICK_POWDER] = sText_HoldEffectQuickPowder, + [HOLD_EFFECT_ADAMANT_ORB] = sText_HoldEffectAdamantOrb, + [HOLD_EFFECT_LUSTROUS_ORB] = sText_HoldEffectLustrousOrb, + [HOLD_EFFECT_GRISEOUS_ORB] = sText_HoldEffectGriseousOrb, + [HOLD_EFFECT_GRACIDEA] = sText_HoldEffectGracidea, + [HOLD_EFFECT_RESIST_BERRY] = sText_HoldEffectResistBerry, + [HOLD_EFFECT_POWER_ITEM] = sText_HoldEffectPowerItem, + [HOLD_EFFECT_RESTORE_PCT_HP] = sText_HoldEffectRestorePctHp, + //[HOLD_EFFECT_MICLE_BERRY] = sText_HoldEffectMicleBerry, + //[HOLD_EFFECT_CUSTAP_BERRY] = sText_HoldEffectCustapBerry, + //[HOLD_EFFECT_JABOCA_BERRY] = sText_HoldEffectJabocaBerry, + //[HOLD_EFFECT_ROWAP_BERRY] = sText_HoldEffectRowapBerry, + //[HOLD_EFFECT_KEE_BERRY] = sText_HoldEffectKeeBerry, + //[HOLD_EFFECT_MARANGA_BERRY] = sText_HoldEffectMarangaBerry, + [HOLD_EFFECT_FLOAT_STONE] = sText_HoldEffectFloatStone, + [HOLD_EFFECT_EVIOLITE] = sText_HoldEffectEviolite, + [HOLD_EFFECT_ASSAULT_VEST] = sText_HoldEffectAssaultVest, + [HOLD_EFFECT_DRIVE] = sText_HoldEffectDrive, + [HOLD_EFFECT_GEMS] = sText_HoldEffectGems, + [HOLD_EFFECT_ROCKY_HELMET] = sText_HoldEffectRockyHelmet, + [HOLD_EFFECT_AIR_BALLOON] = sText_HoldEffectAirBalloon, + [HOLD_EFFECT_RED_CARD] = sText_HoldEffectRedCard, + [HOLD_EFFECT_RING_TARGET] = sText_HoldEffectRingTarget, + [HOLD_EFFECT_BINDING_BAND] = sText_HoldEffectBindingBand, + [HOLD_EFFECT_EJECT_BUTTON] = sText_HoldEffectEjectButton, + [HOLD_EFFECT_ABSORB_BULB] = sText_HoldEffectAbsorbBulb, + [HOLD_EFFECT_CELL_BATTERY] = sText_HoldEffectCellBattery, + [HOLD_EFFECT_FAIRY_POWER] = sText_HoldEffectFairyPower, + [HOLD_EFFECT_MEGA_STONE] = sText_HoldEffectMegaStone, + [HOLD_EFFECT_SAFETY_GOOGLES] = sText_HoldEffectSafetyGoogles, + [HOLD_EFFECT_LUMINOUS_MOSS] = sText_HoldEffectLuminousMoss, + [HOLD_EFFECT_SNOWBALL] = sText_HoldEffectSnowball, + [HOLD_EFFECT_WEAKNESS_POLICY] = sText_HoldEffectWeaknessPolicy, + [HOLD_EFFECT_PROTECTIVE_PADS] = sText_HoldEffectProtectivePads, + [HOLD_EFFECT_TERRAIN_EXTENDER] = sText_HoldEffectTerrainExtender, + [HOLD_EFFECT_SEEDS] = sText_HoldEffectSeeds, + [HOLD_EFFECT_ADRENALINE_ORB] = sText_HoldEffectAdrenalineOrb, + [HOLD_EFFECT_MEMORY] = sText_HoldEffectMemory, + [HOLD_EFFECT_PLATE] = sText_HoldEffectPlate, + [HOLD_EFFECT_UTILITY_UMBRELLA] = sText_HoldEffectUtilityUmbrella, + [HOLD_EFFECT_EJECT_PACK] = sText_HoldEffectEjectPack, + [HOLD_EFFECT_ROOM_SERVICE] = sText_HoldEffectRoomService, + [HOLD_EFFECT_BLUNDER_POLICY] = sText_HoldEffectBlunderPolicy, + [HOLD_EFFECT_HEAVY_DUTY_BOOTS] = sText_HoldEffectHeavyDutyBoots, + [HOLD_EFFECT_THROAT_SPRAY] = sText_HoldEffectThroatSpray, +}; +static const u8 *GetHoldEffectName(u16 holdEffect) +{ + if (holdEffect > ARRAY_COUNT(sHoldEffectNames)) + return sHoldEffectNames[0]; + return sHoldEffectNames[holdEffect]; +} diff --git a/src/battle_main.c b/src/battle_main.c index 9ac4af0df8..d7a5681b21 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3051,6 +3051,7 @@ void SwitchInClearSetData(void) ClearBattlerMoveHistory(gActiveBattler); ClearBattlerAbilityHistory(gActiveBattler); + ClearBattlerItemEffectHistory(gActiveBattler); } void FaintClearSetData(void) @@ -3139,6 +3140,7 @@ void FaintClearSetData(void) ClearBattlerMoveHistory(gActiveBattler); ClearBattlerAbilityHistory(gActiveBattler); + ClearBattlerItemEffectHistory(gActiveBattler); UndoFormChange(gBattlerPartyIndexes[gActiveBattler], GET_BATTLER_SIDE(gActiveBattler)); if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) UndoMegaEvolution(gBattlerPartyIndexes[gActiveBattler]); From 18f5d9f0a3bf0e42cce12653139ec667e8590dce Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 26 Jan 2021 17:11:55 -0700 Subject: [PATCH 28/36] better AI_TryToFaint --- src/battle_ai_main.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 932b19037e..6ba62343f0 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -2411,34 +2411,41 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) -{ - s32 dmg; - u8 result; - +{ if (IsTargetingPartner(battlerAtk, battlerDef)) - return score; // don't try to faint your ally ever + return score; - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power == 0) + if (gBattleMoves[move].power == 0) return score; // can't make anything faint with no power if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0) && gBattleMoves[move].effect != EFFECT_EXPLOSION) { - // AI_TryToFaint_Can - if (IsAiFaster(AI_CHECK_FASTER) || TestMoveFlags(move, FLAG_HIGH_CRIT)) + // this move can faint the target + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 || GetMovePriority(battlerAtk, move) > 0) score += 4; else score += 2; } else { + // this move isn't expected to faint the target + if (TestMoveFlags(move, FLAG_HIGH_CRIT)) + score += 2; // crit makes it more likely to make them faint + if (GetMoveDamageResult(move) == MOVE_POWER_DISCOURAGED) score--; - if (AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x4) + switch (AI_GetMoveEffectiveness(move, battlerAtk, battlerDef)) { - // AI_TryToFaint_DoubleSuperEffective - if ((Random() % 256) >= 80) + case AI_EFFECTIVENESS_x4: + score += 4; + break; + case AI_EFFECTIVENESS_x2: + if (AI_RandLessThan(176)) score += 2; + else + score++; + break; } } From b9e425252d01811f5ae1537e3323f59d4721a1d2 Mon Sep 17 00:00:00 2001 From: Evan Date: Wed, 27 Jan 2021 08:33:43 -0700 Subject: [PATCH 29/36] remove duplicate non-user check --- src/battle_ai_main.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 6ba62343f0..4af3ba4fcc 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -545,22 +545,20 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { score -= 10; } - + + // check off screen + if (gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) != 1) + RETURN_SCORE_MINUS(20); // if target off screen and we go first, don't use move + // check if negates type - if (!(gBattleMoves[move].target & MOVE_TARGET_USER)) + switch (effectiveness) { - if (gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) != 1) - RETURN_SCORE_MINUS(20); // if target off screen and we go first, don't use move - - switch (effectiveness) - { - case AI_EFFECTIVENESS_x0: - RETURN_SCORE_MINUS(20); - break; - case AI_EFFECTIVENESS_x0_25: - RETURN_SCORE_MINUS(10); - break; - } + case AI_EFFECTIVENESS_x0: + RETURN_SCORE_MINUS(20); + break; + case AI_EFFECTIVENESS_x0_25: + RETURN_SCORE_MINUS(10); + break; } // target ability checks @@ -2422,7 +2420,7 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // this move can faint the target if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 || GetMovePriority(battlerAtk, move) > 0) - score += 4; + score += 4; // we go first or we're using priority move else score += 2; } From 1405f04e1e8bf18022d5b5929f932405cb19ac03 Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 7 Feb 2021 12:39:23 -0700 Subject: [PATCH 30/36] ai understands constant-damage effects --- src/battle_ai_main.c | 2 +- src/battle_ai_util.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 4af3ba4fcc..c45ccc311b 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -188,7 +188,7 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves) move = gBattleMons[sBattler_AI].moves[i]; if (gBattleMoves[move].power != 0 && !(moveLimitations & gBitTable[i])) { - dmg = AI_CalcDamage(move, sBattler_AI, gBattlerTarget) * (100 - (Random() % 10)) / 100; + dmg = AI_CalcDamage(move, sBattler_AI, gBattlerTarget); if (dmg == 0) dmg = 1; } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 018dc55a51..bbfae9bda1 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -721,6 +721,35 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) GET_MOVE_TYPE(move, moveType); dmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, AI_GetIfCrit(move, battlerAtk, battlerDef), FALSE, FALSE); + // handle dynamic move damage + switch (gBattleMoves[move].effect) + { + case EFFECT_LEVEL_DAMAGE: + dmg = gBattleMons[battlerAtk].level; + break; + case EFFECT_DRAGON_RAGE: + dmg = 40; + break; + case EFFECT_SONICBOOM: + dmg = 20; + break; + case EFFECT_PSYWAVE: + { + u32 randDamage; + if (B_PSYWAVE_DMG >= GEN_6) + randDamage = (Random() % 101); + else + randDamage = (Random() % 11) * 10; + dmg = gBattleMons[battlerAtk].level * (randDamage + 50) / 100; + } + break; + //case EFFECT_METAL_BURST: + //case EFFECT_COUNTER: + default: + dmg *= (100 - (Random() % 10)) / 100; // add random factor + break; + } + RestoreBattlerData(battlerAtk); RestoreBattlerData(battlerDef); From 4782f713f2e0cde617a06add661ce57fdec2743d Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 12 Feb 2021 08:57:57 -0700 Subject: [PATCH 31/36] update semi invulnerable state check --- include/battle_ai_util.h | 1 + src/battle_ai_main.c | 2 +- src/battle_ai_util.c | 23 +++++++++++++++-------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index fffd85c5b5..547ec060f8 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -115,6 +115,7 @@ bool32 IsStatLoweringEffect(u16 effect); bool32 IsStatRaisingEffect(u16 effect); bool32 IsAttackBoostMoveEffect(u16 effect); bool32 IsUngroundingEffect(u16 effect); +bool32 IsSemiInvulnerable(u8 battlerDef, u16 move); // status checks bool32 CanBeBurned(u8 battler, u16 ability); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index c45ccc311b..7f76e35f9d 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -547,7 +547,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // check off screen - if (gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) != 1) + if (IsSemiInvulnerable(battlerDef, move) && effect != EFFECT_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) != 1) RETURN_SCORE_MINUS(20); // if target off screen and we go first, don't use move // check if negates type diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index bbfae9bda1..8d55776030 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1339,16 +1339,23 @@ u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbil return calc; } +bool32 IsSemiInvulnerable(u8 battlerDef, u16 move) +{ + if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) + return TRUE; + else if (!TestMoveFlags(move, FLAG_HIT_IN_AIR) && gStatuses3[battlerDef] & STATUS3_ON_AIR) + return TRUE; + else if (!TestMoveFlags(move, FLAG_DMG_UNDERWATER) && gStatuses3[battlerDef] & STATUS3_UNDERWATER) + return TRUE; + else if (!TestMoveFlags(move, FLAG_DMG_UNDERGROUND) && gStatuses3[battlerDef] & STATUS3_UNDERGROUND) + return TRUE; + else + return FALSE; +} + bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) { - // never hits - if (gStatuses3[battlerDef] & (STATUS3_SEMI_INVULNERABLE)) - return FALSE; - - if ((gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) - || (!TestMoveFlags(move, FLAG_HIT_IN_AIR) && gStatuses3[battlerDef] & STATUS3_ON_AIR) - || (!TestMoveFlags(move, FLAG_DMG_UNDERGROUND) && gStatuses3[battlerDef] & STATUS3_UNDERGROUND) - || (!TestMoveFlags(move, FLAG_DMG_UNDERWATER) && gStatuses3[battlerDef] & STATUS3_UNDERWATER)) + if (IsSemiInvulnerable(battlerDef, move)) return FALSE; //TODO - anticipate protect move? From 0664daf384eee36e3f0a7c4b3d53b4f08ade4b72 Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 12 Feb 2021 11:02:10 -0700 Subject: [PATCH 32/36] fix some post-merge errors --- include/battle_ai_util.h | 1 - include/battle_util.h | 1 + src/battle_ai_main.c | 13 ++++++------- src/battle_ai_util.c | 23 ++--------------------- src/battle_util.c | 2 +- 5 files changed, 10 insertions(+), 30 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 547ec060f8..f83fa85222 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -108,7 +108,6 @@ bool32 HasHealingEffect(u32 battler); bool32 IsTrappingMoveEffect(u16 effect); bool32 HasTrappingMoveEffect(u8 battler); bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move); -bool32 IsThawingMove(u16 move); bool32 HasThawingMove(u8 battlerId); bool32 IsStatRaisingEffect(u16 effect); bool32 IsStatLoweringEffect(u16 effect); diff --git a/include/battle_util.h b/include/battle_util.h index b26ea09398..cae5f7338d 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -135,6 +135,7 @@ struct Pokemon *GetBattlerPartyData(u8 battlerId); bool32 CanFling(u8 battlerId); bool32 IsTelekinesisBannedSpecies(u16 species); bool32 IsHealBlockPreventingMove(u32 battler, u32 move); +bool32 IsThawingMove(u8 battlerId, u16 move); // ability checks bool32 IsRolePlayBannedAbilityAtk(u16 ability); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 7f76e35f9d..55080a7561 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -108,7 +108,7 @@ void BattleAI_SetupItems(void) if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER) && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_SECRET_BASE | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_x2000000) + | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_RECORDED_LINK) ) ) { @@ -528,10 +528,9 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // handle negative checks on non-user target // check powder moves - if (TestMoveFlags(move, FLAG_POWDER)) + if (TestMoveFlags(move, FLAG_POWDER) && !IsAffectedByPowder(battlerDef, AI_DATA->defAbility, AI_DATA->defHoldEffect)) { - if (!IsAffectedByPowder(battlerDef, AI_DATA->defAbility, AI_DATA->defHoldEffect)) - score -= 10; + RETURN_SCORE_MINUS(20); } // check ground immunities @@ -543,11 +542,11 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || (gStatuses3[battlerDef] & (STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS))) && move != MOVE_THOUSAND_ARROWS) { - score -= 10; + RETURN_SCORE_MINUS(20); } // check off screen - if (IsSemiInvulnerable(battlerDef, move) && effect != EFFECT_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) != 1) + if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) != 1) RETURN_SCORE_MINUS(20); // if target off screen and we go first, don't use move // check if negates type @@ -2883,7 +2882,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; // check thawing moves - if ((gBattleMons[battlerAtk].status1 & STATUS1_FREEZE) && IsThawingMove(move)) + if ((gBattleMons[battlerAtk].status1 & STATUS1_FREEZE) && IsThawingMove(battlerAtk, move)) score += (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) ? 20 : 10; // ability checks diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 8d55776030..9ede3ae991 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1922,25 +1922,6 @@ bool32 HasTrappingMoveEffect(u8 battler) return FALSE; } -bool32 IsThawingMove(u16 move) -{ - switch (move) - { - case MOVE_FLAME_WHEEL: - case MOVE_SACRED_FIRE: - case MOVE_FLARE_BLITZ: - case MOVE_SCALD: - case MOVE_SCORCHING_SANDS: - case MOVE_FUSION_FLARE: - case MOVE_STEAM_ERUPTION: - case MOVE_BURN_UP: - case MOVE_PYRO_BALL: - return TRUE; - default: - return FALSE; - } -} - bool32 HasThawingMove(u8 battlerId) { s32 i; @@ -1948,7 +1929,7 @@ bool32 HasThawingMove(u8 battlerId) for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && IsThawingMove(moves[i])) + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && IsThawingMove(battlerId, moves[i])) return TRUE; } @@ -2545,7 +2526,7 @@ bool32 CanKnockOffItem(u8 battler, u16 item) if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK - | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_SECRET_BASE #if defined B_TRAINERS_KNOCK_OFF_ITEMS | BATTLE_TYPE_TRAINER diff --git a/src/battle_util.c b/src/battle_util.c index e06c17d664..7aef03591d 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2963,7 +2963,7 @@ void TryClearRageAndFuryCutter(void) } } -static bool32 IsThawingMove(u8 battlerId, u16 move) +bool32 IsThawingMove(u8 battlerId, u16 move) { switch (move) { From 49e41a2d3b134ab3d9e1275620499be47440f6a2 Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 14 Feb 2021 09:11:29 -0700 Subject: [PATCH 33/36] fix ShouldSetScreen (thx Syreldar) --- src/battle_ai_main.c | 2 +- src/battle_ai_util.c | 53 +++++++++++++++++--------------------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 55080a7561..2e8342204c 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -3232,7 +3232,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_LIGHT_SCREEN: case EFFECT_REFLECT: case EFFECT_AURORA_VEIL: - if (ShouldSetScreen(battlerAtk, battlerDef, move)) + if (ShouldSetScreen(battlerAtk, battlerDef, moveEffect)) { score += 5; if (AI_DATA->atkHoldEffect == HOLD_EFFECT_LIGHT_CLAY) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 9ede3ae991..1c55d07986 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -2891,41 +2891,28 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent) bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect) { u8 atkSide = GetBattlerSide(battlerAtk); - - if (gSideTimers[atkSide].auroraVeilTimer != 0) + switch (moveEffect) { - bool8 defHasPhysical = HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL); - bool8 defHasSpecial = HasMoveWithSplit(battlerDef, SPLIT_SPECIAL); - - switch (moveEffect) - { - case EFFECT_AURORA_VEIL: - if (gBattleWeather & WEATHER_HAIL_ANY - && !((gSideStatuses[atkSide] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN)))) - return TRUE; - break; - case EFFECT_REFLECT: - if (SideHasMoveSplit(battlerDef, SPLIT_PHYSICAL)) - { - if (!defHasPhysical && !defHasSpecial) - return TRUE; // Target has no attacking moves so no point in doing Light Screen check - - if (defHasPhysical || !HasMoveEffect(battlerAtk, EFFECT_LIGHT_SCREEN) || !defHasSpecial) - return TRUE; - } - break; - case EFFECT_LIGHT_SCREEN: - if (SideHasMoveSplit(battlerDef, SPLIT_SPECIAL)) - { - if (!defHasPhysical && !defHasSpecial) - return TRUE; //Target has no attacking moves so no point in doing Light Screen check - - if (defHasSpecial || !HasMoveEffect(battlerAtk, EFFECT_REFLECT) || !defHasPhysical) - return TRUE; - } - break; - } + 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 (gBattleWeather & WEATHER_HAIL_ANY + && !(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 (HasMoveWithSplit(battlerDef, SPLIT_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 (HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) + && !(gSideStatuses[atkSide] & SIDE_STATUS_LIGHTSCREEN)) + return TRUE; + break; } + return FALSE; } From 167aaef8f6198b1f16e96e8f06df9af7afa8de69 Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 14 Feb 2021 09:20:42 -0700 Subject: [PATCH 34/36] add faint check to AI_SetupFirstTurn (thx Syreldar) --- src/battle_ai_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 2e8342204c..fcafd648c2 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -4533,6 +4533,15 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsTargetingPartner(battlerAtk, battlerDef) || gBattleResults.battleTurnCounter != 0) return score; + + if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 + && 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 (gBattleMoves[move].effect) { case EFFECT_ATTACK_UP: From d65d5cb8fd7e87dff287500da218cbedfad52e9f Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 14 Feb 2021 09:37:04 -0700 Subject: [PATCH 35/36] add AI_FLAG_SMART_SWITCHING, some burn checks --- include/battle_ai_util.h | 1 + include/constants/battle_ai.h | 1 + src/battle_ai_main.c | 34 +++++++++++++++++++++------------- src/battle_ai_util.c | 16 ++++++++++++++++ 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index f83fa85222..db33a7ff11 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -81,6 +81,7 @@ u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); u16 *GetMovesArray(u32 battler); bool32 IsConfusionMoveEffect(u16 moveEffect); bool32 HasMove(u32 battlerId, u32 move); +bool32 HasOnlyMovesWithSplit(u32 battlerId, u32 split, bool32 onlyOffensive); bool32 HasMoveWithSplit(u32 battler, u32 split); bool32 HasMoveWithType(u32 battler, u8 type); bool32 HasMoveWithTypeAndSplit(u32 battler, u8 type, u8 split); diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 6b17a53795..7f56fbcedc 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -53,6 +53,7 @@ #define AI_FLAG_PREFER_STATUS_MOVES (1 << 12) // 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 << 13) // AI stalls battle and prefers secondary damage/trapping/etc. TODO not finished #define AI_FLAG_SCREENER (1 << 14) // AI prefers screening effects like reflect, mist, etc. TODO unfinished +#define AI_FLAG_SMART_SWITCHING (1 << 15) // AI includes a lot more switching checks // 'other' ai logic flags #define AI_FLAG_ROAMING (1 << 29) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index fcafd648c2..18c7a67f26 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -2864,18 +2864,6 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // check damage if (gBattleMoves[move].power != 0 && GetMoveDamageResult(move) == MOVE_POWER_WEAK) score--; - - /*if (CountUsablePartyMons(battlerAtk) != 0 - && GetMoveDamageResult(move) != 0 && !HasMoveWithSplit(battlerAtk, SPLIT_STATUS) - && GetCurrDamageHpPercent(battlerAtk, battlerDef) < 30) - { - if (GetCurrDamageHpPercent(battlerAtk, battlerDef) > 20) - score--; - else if (GetMoveDamageResult(move) == MOVE_POWER_BEST) - score -= 2; - else - score -= 3; - }*/ // check status move preference if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_PREFER_STATUS_MOVES && IS_MOVE_STATUS(move) && effectiveness != AI_EFFECTIVENESS_x0) @@ -2885,6 +2873,25 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if ((gBattleMons[battlerAtk].status1 & STATUS1_FREEZE) && IsThawingMove(battlerAtk, move)) score += (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) ? 20 : 10; + // check burn + if (gBattleMons[battlerAtk].status1 & STATUS1_BURN) + { + switch (AI_DATA->atkAbility) + { + case ABILITY_GUTS: + break; + case ABILITY_NATURAL_CURE: + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING + && HasOnlyMovesWithSplit(battlerAtk, SPLIT_PHYSICAL, TRUE)) + score = 90; // Force switch if all your attacking moves are physical and you have Natural Cure. + break; + default: + if (IS_MOVE_PHYSICAL(move) && gBattleMoves[move].effect != EFFECT_FACADE) + score -= 2; + break; + } + } + // ability checks switch (AI_DATA->atkAbility) { @@ -4534,7 +4541,8 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || gBattleResults.battleTurnCounter != 0) return score; - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING + && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 && CanTargetFaintAi(battlerDef, battlerAtk) && GetMovePriority(battlerAtk, move) == 0) { diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 1c55d07986..2e1dc71232 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1755,6 +1755,22 @@ u16 *GetMovesArray(u32 battler) return gBattleResources->battleHistory->usedMoves[battler]; } +bool32 HasOnlyMovesWithSplit(u32 battlerId, u32 split, 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] != 0xFFFF && GetBattleMoveSplit(moves[i]) != split) + return FALSE; + } + + return TRUE; +} + bool32 HasMoveWithSplit(u32 battler, u32 split) { u32 i; From 54b03a474da439588146f9d9e4afe301992c626f Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Sun, 23 May 2021 12:22:07 -0600 Subject: [PATCH 36/36] fix SIDE_STATUS_SCREEN_ANY --- include/constants/battle.h | 2 +- src/battle_ai_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/constants/battle.h b/include/constants/battle.h index b629b94bff..73769c5099 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -221,7 +221,7 @@ #define SIDE_STATUS_MAT_BLOCK (1 << 21) #define SIDE_STATUS_HAZARDS_ANY (SIDE_STATUS_SPIKES | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_STEALTH_ROCK) -#define SIDE_STATUS_SCREEEN_ANY (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL) +#define SIDE_STATUS_SCREEN_ANY (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL) // Field affecting statuses. #define STATUS_FIELD_MAGIC_ROOM (1 << 0) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 18c7a67f26..6735997d15 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -3861,7 +3861,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) switch (move) { case MOVE_DEFOG: - if (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST)) + if (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST)) { score += 3; }