diff --git a/include/battle.h b/include/battle.h index ae73365aad..a95dfc9066 100644 --- a/include/battle.h +++ b/include/battle.h @@ -360,6 +360,7 @@ struct AI_ThinkingStruct u8 movesetIndex; u16 moveConsidered; s32 score[MAX_MON_MOVES]; + s32 predictedScore[MAX_MON_MOVES][MAX_BATTLERS_COUNT]; u32 funcResult; u32 aiFlags[MAX_BATTLERS_COUNT]; u8 aiAction; diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index b21b20751d..35edd0c10e 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -64,6 +64,12 @@ typedef s32 (*AiScoreFunc)(u32, u32, u32, s32); AI_THINKING_STRUCT->score[movesetIndex] = val; \ } while (0) \ +#define SET_PREDICTED_SCORE(battler, movesetIndex, val) \ + do \ + { \ + AI_THINKING_STRUCT->predictedScore[movesetIndex][battler] = val; \ + } while (0) \ + #define ADJUST_SCORE(val) \ do \ { \ diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 8ba2c72096..0dbc689844 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -43,13 +43,14 @@ #define AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE (1 << 22) // AI adds score to highest damage move regardless of accuracy or secondary effect #define AI_FLAG_PREDICT_SWITCH (1 << 23) // AI will predict the player's switches and switchins based on how it would handle the situation. Recommend using AI_FLAG_OMNISCIENT #define AI_FLAG_PREDICT_INCOMING_MON (1 << 24) // AI will score against the predicting incoming mon if it predicts the player to switch. Requires AI_FLAG_PREDICT_SWITCH +#define AI_FLAG_PREDICT_MOVES (1 << 25) // #define AI_FLAG_COUNT 25 // The following options are enough to have a basic/smart trainer. Any other addtion could make the trainer worse/better depending on the flag #define AI_FLAG_BASIC_TRAINER (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY) #define AI_FLAG_SMART_TRAINER (AI_FLAG_BASIC_TRAINER | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_WEIGH_ABILITY_PREDICTION) -#define AI_FLAG_PREDICTION (AI_FLAG_PREDICT_SWITCH | AI_FLAG_PREDICT_INCOMING_MON) +#define AI_FLAG_PREDICTION (AI_FLAG_PREDICT_SWITCH | AI_FLAG_PREDICT_INCOMING_MON | AI_FLAG_PREDICT_MOVES) // 'other' ai logic flags #define AI_FLAG_DYNAMIC_FUNC (1 << 28) // Create custom AI functions for specific battles via "setdynamicaifunc" cmd diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 6c651d6639..ac474b1066 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -238,8 +238,9 @@ void BattleAI_SetupFlags(void) void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) { - u32 moveLimitations; + u32 moveLimitations, moveLimitationsTarget; u32 flags[MAX_BATTLERS_COUNT]; + u32 moveIndex; // Clear AI data but preserve the flags. memcpy(&flags[0], &AI_THINKING_STRUCT->aiFlags[0], sizeof(u32) * MAX_BATTLERS_COUNT); @@ -249,7 +250,7 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) moveLimitations = AI_DATA->moveLimitations[battler]; // Conditional score reset, unlike Ruby. - for (u32 moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) + for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { if (moveLimitations & (1u << moveIndex)) SET_SCORE(battler, moveIndex, 0); @@ -263,6 +264,22 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) gBattlerTarget = SetRandomTarget(battler); gAiBattleData->chosenTarget[battler] = gBattlerTarget; + + // Initialize move prediction scores + if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVES) + { + moveLimitationsTarget = AI_DATA->moveLimitations[gBattlerTarget]; + + for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) + { + if (moveLimitations & (1u << moveIndex)) + SET_PREDICTED_SCORE(gBattlerTarget, moveIndex, 0); + if (defaultScoreMoves & 1) + SET_PREDICTED_SCORE(gBattlerTarget, moveIndex, AI_SCORE_DEFAULT); + else + SET_PREDICTED_SCORE(gBattlerTarget, moveIndex, 0); + } + } } u32 BattleAI_ChooseMoveOrAction(u32 battler) diff --git a/test/battle/ai/ai_flag_predict_move.c b/test/battle/ai/ai_flag_predict_move.c new file mode 100644 index 0000000000..c918e4a55e --- /dev/null +++ b/test/battle/ai/ai_flag_predict_move.c @@ -0,0 +1,15 @@ +#include "global.h" +#include "test/battle.h" +#include "battle_ai_util.h" + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_MOVE: AI will predict player's move") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_MOVE); + PLAYER(SPECIES_VAPOREON) { Moves(MOVE_SURF, MOVE_TACKLE); } + OPPONENT(SPECIES_NUMEL) { Moves(MOVE_TACKLE); } + OPPONENT(SPECIES_VAPOREON) { Ability(ABILITY_WATER_ABSORB); Moves(MOVE_TACKLE); } + } WHEN { + TURN { MOVE(player, MOVE_SURF); EXPECT_SWITCH(opponent, 1); } + } +}