diff --git a/docs/tutorials/ai_flags.md b/docs/tutorials/ai_flags.md index 7910049fbe..9f39090b65 100644 --- a/docs/tutorials/ai_flags.md +++ b/docs/tutorials/ai_flags.md @@ -147,6 +147,10 @@ AI has full knowledge of player moves, abilities, and hold items, and can use th ## `AI_FLAG_ASSUME_STAB` A significantly more restricted version of `AI_FLAG_OMNISCIENT`, the AI only knows the player's STAB moves, as their existence would be reasonable to assume in almost any case. +## `AI_FLAG_ASSUME_POWERFUL_STATUS` +A more restricted version of `AI_FLAG_OMNISCIENT`. The AI has a _chance_ to know if the player has certain iconic status moves, plus also Fake Out and fixed percentage moves like Super Fang. + + ## `AI_FLAG_SMART_MON_CHOICES` Affects what the AI chooses to send out after a switch. AI will make smarter decisions when choosing which mon to send out mid-battle and after a KO, which are handled separately. Automatically included when `AI_FLAG_SMART_SWITCHING` is enabled. diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index b0ad69f5d9..1e03090dde 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -61,6 +61,8 @@ bool32 IsAiVsAiBattle(void); bool32 BattlerHasAi(u32 battlerId); bool32 IsAiBattlerAware(u32 battlerId); bool32 IsAiBattlerAssumingStab(void); +bool32 IsAiBattlerAssumingPowerfulStatus(void); +bool32 ShouldRecordStatusMove(u32 move); void ClearBattlerMoveHistory(u32 battlerId); void RecordLastUsedMoveBy(u32 battlerId, u32 move); void RecordAllMoves(u32 battler); diff --git a/include/config/ai.h b/include/config/ai.h index 57fc7ecb60..be091649af 100644 --- a/include/config/ai.h +++ b/include/config/ai.h @@ -76,6 +76,11 @@ // AI_FLAG_ASSUME_STAB settings #define ASSUME_STAB_SEES_ABILITY FALSE // Flag also gives omniscience for player's ability. Can use AI_FLAG_WEIGH_ABILITY_PREDICTION instead for smarter prediction without omniscience. +// AI_FLAG_ASSUME_POWERFUL_STATUS settings +#define ASSUME_POWERFUL_STATUS_HIGH_ODDS 95 // Chance for AI to see extremely likely moves for a pokemon to have, like Spore +#define ASSUME_POWERFUL_STATUS_MEDIUM_ODDS 75 // Chance for AI to see moderately likely moves for a pokemon to have, like Protect +#define ASSUME_POWERFUL_STATUS_LOW_ODDS 50 // Chance for AI to see niche moves a pokemon may have but probably won't, like Trick Room or Speed Swap + // AI_FLAG_SMART_SWITCHING settings #define SMART_SWITCHING_OMNISCIENT FALSE // AI will use omniscience for switching calcs, regardless of omniscience setting otherwise diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 4fc13aaa1b..fa2a96ee5d 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -34,8 +34,9 @@ #define AI_FLAG_PREDICT_MOVE (1 << 26) // AI will predict the player's move based on what move it would use in the same situation. Recommend using AI_FLAG_OMNISCIENT #define AI_FLAG_SMART_TERA (1 << 27) // AI will make smarter decisions when choosing whether to terrastalize (default is to always tera whenever available). #define AI_FLAG_ASSUME_STAB (1 << 28) // AI knows player's STAB moves, but nothing else. Restricted version of AI_FLAG_OMNISCIENT. +#define AI_FLAG_ASSUME_POWERFUL_STATUS (1 << 29) // AI has a chance to know certain non-damaging moves, and also Fake Out and Super Fang. Restricted version of AI_FLAG_OMNISCIENT. -#define AI_FLAG_COUNT 29 +#define AI_FLAG_COUNT 30 // Flags at and after 32 need different formatting, as in // #define AI_FLAG_PLACEHOLDER ((u64)1 << 32) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 43d01dfa2e..a69edaa48f 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -544,6 +544,17 @@ void RecordMovesBasedOnStab(u32 battler) } } +void RecordPowerfulStatusMoves(u32 battler) +{ + u32 i; + for (i = 0; i < MAX_MON_MOVES; i++) + { + u32 playerMove = gBattleMons[battler].moves[i]; + if (ShouldRecordStatusMove(playerMove)) + RecordKnownMove(battler, playerMove); + } +} + void SetBattlerAiData(u32 battler, struct AiLogicData *aiData) { u32 ability, holdEffect; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 48403d4e11..b6a208a9c7 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -249,6 +249,96 @@ void SaveBattlerData(u32 battlerId) gAiThinkingStruct->saved[battlerId].types[1] = gBattleMons[battlerId].types[1]; } +bool32 ShouldRecordStatusMove(u32 move) +{ + u32 rand = Random() % 100; + + if (rand >= ASSUME_POWERFUL_STATUS_HIGH_ODDS) + return FALSE; + + switch (GetMoveEffect(move)) + { + // variable odds by additional effect + case EFFECT_NON_VOLATILE_STATUS: + if (GetMoveNonVolatileStatus(move) == MOVE_EFFECT_SLEEP) + return TRUE; + else if (rand < ASSUME_POWERFUL_STATUS_MEDIUM_ODDS) + return TRUE; + break; + // High odds + case EFFECT_AURORA_VEIL: + case EFFECT_CHILLY_RECEPTION: + case EFFECT_CONVERSION: + case EFFECT_FIRST_TURN_ONLY: + case EFFECT_FOLLOW_ME: + case EFFECT_INSTRUCT: + case EFFECT_JUNGLE_HEALING: + case EFFECT_REVIVAL_BLESSING: + case EFFECT_SHED_TAIL: + case EFFECT_STICKY_WEB: + return TRUE; + // Medium odds + case EFFECT_AFTER_YOU: + case EFFECT_DEFOG: + case EFFECT_ENCORE: + case EFFECT_HAZE: + case EFFECT_HEAL_BELL: + case EFFECT_HEALING_WISH: + case EFFECT_LIFE_DEW: + case EFFECT_MEMENTO: + case EFFECT_PARTING_SHOT: + case EFFECT_PROTECT: + case EFFECT_RESTORE_HP: + case EFFECT_ROAR: + case EFFECT_TAUNT: + case EFFECT_TAILWIND: + case EFFECT_TELEPORT: + case EFFECT_TRICK: + // defoggables / screens and hazards + case EFFECT_LIGHT_SCREEN: + case EFFECT_REFLECT: + case EFFECT_SPIKES: + case EFFECT_STEALTH_ROCK: + case EFFECT_TOXIC_SPIKES: + // field status + case EFFECT_HAIL: + case EFFECT_RAIN_DANCE: + case EFFECT_SANDSTORM: + case EFFECT_SNOWSCAPE: + case EFFECT_SUNNY_DAY: + case EFFECT_TRICK_ROOM: + case EFFECT_ELECTRIC_TERRAIN: + case EFFECT_GRASSY_TERRAIN: + case EFFECT_MISTY_TERRAIN: + case EFFECT_PSYCHIC_TERRAIN: + if (rand < ASSUME_POWERFUL_STATUS_MEDIUM_ODDS) + return TRUE; + break; + // Low odds + case EFFECT_COURT_CHANGE: + case EFFECT_DOODLE: + case EFFECT_ENTRAINMENT: + case EFFECT_FIXED_PERCENT_DAMAGE: + case EFFECT_GASTRO_ACID: + case EFFECT_GUARD_SPLIT: + case EFFECT_IMPRISON: + case EFFECT_PERISH_SONG: + case EFFECT_POWER_SPLIT: + case EFFECT_QUASH: + case EFFECT_ROLE_PLAY: + case EFFECT_SKILL_SWAP: + case EFFECT_SPEED_SWAP: + case EFFECT_WORRY_SEED: + if (rand < ASSUME_POWERFUL_STATUS_LOW_ODDS) + return TRUE; + break; + default: + break; + } + + return FALSE; +} + static bool32 ShouldFailForIllusion(u32 illusionSpecies, u32 battlerId) { u32 i, j;