Adds Powerful status move flag (#4125)

* Adds Powerful status move flag

* fix flag

* fixed final issues

* review changes
This commit is contained in:
Alex 2024-02-18 15:05:08 +01:00 committed by GitHub
parent 7ab23cf426
commit 7694628296
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 213 additions and 49 deletions

View file

@ -29,7 +29,8 @@
#define STAT_CHANGE_ACC 10
#define STAT_CHANGE_EVASION 11
#define BEST_DAMAGE_MOVE 1 // Move with the most amount of hits with the best accuracy/effect
#define BEST_DAMAGE_MOVE 1 // Move with the most amount of hits with the best accuracy/effect
#define POWERFUL_STATUS_MOVE 10 // Moves with this score will be chosen over a move that faints target
// Temporary scores that are added together to determine a final score at the at of AI_CalcMoveScore
#define WEAK_EFFECT 1

View file

@ -189,6 +189,6 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl
s32 AI_CheckMoveEffects(u32 battlerAtk, u32 battlerDef, u32 move, s32 score, struct AiLogicData *aiData, u32 predictedMove, bool32 isDoubleBattle);
s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle);
bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef);
s32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData);
bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData);
#endif //GUARD_BATTLE_AI_UTIL_H

View file

@ -354,7 +354,7 @@
#define MOVE_EFFECT_PREVENT_ESCAPE 33
#define MOVE_EFFECT_NIGHTMARE 34
#define MOVE_EFFECT_ALL_STATS_UP 35
#define MOVE_EFFECT_RAPIDSPIN 36
#define MOVE_EFFECT_RAPID_SPIN 36
#define MOVE_EFFECT_REMOVE_STATUS 37
#define MOVE_EFFECT_ATK_DEF_DOWN 38
#define MOVE_EFFECT_ATK_PLUS_2 39

View file

@ -34,20 +34,20 @@
#define AI_FLAG_PREFER_BATON_PASS (1 << 6)
#define AI_FLAG_DOUBLE_BATTLE (1 << 7) // removed, split between AI_FLAG_CHECK_BAD_MOVE & AI_FLAG_CHECK_GOOD_MOVE
#define AI_FLAG_HP_AWARE (1 << 8)
#define AI_FLAG_POWERFUL_STATUS (1 << 9) // AI prefers moves that set up field effects or side statuses, even if the user can faint the target
// New, Trainer Handicap Flags
#define AI_FLAG_NEGATE_UNAWARE (1 << 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
#define AI_FLAG_NEGATE_UNAWARE (1 << 10) // AI is NOT aware of negating effects like wonder room, mold breaker, etc
#define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc
// New, Trainer Strategy Flags
#define AI_FLAG_HELP_PARTNER (1 << 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
#define AI_FLAG_HELP_PARTNER (1 << 12) // AI can try to help partner. If not set, will tend not to target partner
#define AI_FLAG_PREFER_STATUS_MOVES (1 << 13) // AI gets a score bonus for status moves. Should be combined with AI_FLAG_CHECK_BAD_MOVE to prevent using only status moves
#define AI_FLAG_STALL (1 << 14) // AI stalls battle and prefers secondary damage/trapping/etc. TODO not finished
#define AI_FLAG_SMART_SWITCHING (1 << 15) // AI includes a lot more switching checks
#define AI_FLAG_ACE_POKEMON (1 << 16) // AI has an Ace Pokemon. The last Pokemon in the party will not be used until it's the last one remaining.
#define AI_FLAG_OMNISCIENT (1 << 17) // AI has full knowledge of player moves, abilities, hold items
#define AI_FLAG_SMART_MON_CHOICES (1 << 18) // AI will make smarter decisions when choosing which mon to send out mid-battle and after a KO, which are separate decisions. Pairs very well with AI_FLAG_SMART_SWITCHING.
#define AI_FLAG_COUNT 18
#define AI_FLAG_COUNT 19
// 'other' ai logic flags
#define AI_FLAG_ROAMING (1 << 29)

View file

@ -52,6 +52,7 @@ static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_Safari(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) =
@ -65,10 +66,10 @@ static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) =
[6] = AI_PreferBatonPass, // AI_FLAG_PREFER_BATON_PASS
[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
[11] = NULL, // AI_FLAG_HELP_PARTNER
[12] = NULL, // Unused
[9] = AI_PowerfulStatus, // AI_FLAG_POWERFUL_STATUS
[10] = NULL, // AI_FLAG_NEGATE_UNAWARE
[11] = NULL, // AI_FLAG_WILL_SUICIDE
[12] = NULL, // AI_FLAG_HELP_PARTNER
[13] = NULL, // Unused
[14] = NULL, // Unused
[15] = NULL, // Unused
@ -2341,15 +2342,18 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
{
ADJUST_SCORE(-10);
}
else if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM) // Trick Room Up
else if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS))
{
if (GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) // Attacker side slower than target side
ADJUST_SCORE(-10); // Keep the Trick Room up
}
else
{
if (GetBattlerSideSpeedAverage(battlerAtk) >= GetBattlerSideSpeedAverage(battlerDef)) // Attacker side faster than target side
ADJUST_SCORE(-10); // Keep the Trick Room down
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM) // Trick Room Up
{
if (GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) // Attacker side slower than target side
ADJUST_SCORE(-10); // Keep the Trick Room up
}
else
{
if (GetBattlerSideSpeedAverage(battlerAtk) >= GetBattlerSideSpeedAverage(battlerDef)) // Attacker side faster than target side
ADJUST_SCORE(-10); // Keep the Trick Room down
}
}
break;
case EFFECT_MAGIC_ROOM:
@ -3489,8 +3493,6 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(BEST_EFFECT);
if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_LIGHT_CLAY)
ADJUST_SCORE(DECENT_EFFECT);
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SCREENER)
ADJUST_SCORE(DECENT_EFFECT);
}
break;
case EFFECT_REST:
@ -3518,10 +3520,6 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
if (ShouldTrap(battlerAtk, battlerDef, move))
ADJUST_SCORE(GOOD_EFFECT);
break;
case EFFECT_MIST:
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SCREENER)
ADJUST_SCORE(DECENT_EFFECT);
break;
case EFFECT_FOCUS_ENERGY:
case EFFECT_LASER_FOCUS:
if (aiData->abilities[battlerAtk] == ABILITY_SUPER_LUCK
@ -3562,7 +3560,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
case EFFECT_LEECH_SEED:
if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS)
|| gStatuses3[battlerDef] & STATUS3_LEECHSEED
|| HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPIDSPIN)
|| HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN)
|| aiData->abilities[battlerDef] == ABILITY_LIQUID_OOZE
|| aiData->abilities[battlerDef] == ABILITY_MAGIC_GUARD)
break;
@ -3721,7 +3719,13 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
case EFFECT_STEALTH_ROCK:
case EFFECT_STICKY_WEB:
case EFFECT_TOXIC_SPIKES:
score += AI_ShouldSetUpHazards(battlerAtk, battlerDef, aiData);
if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, aiData));
{
if (gDisableStructs[battlerAtk].isFirstTurn)
ADJUST_SCORE(BEST_EFFECT);
else
ADJUST_SCORE(DECENT_EFFECT);
}
break;
case EFFECT_FORESIGHT:
if (aiData->abilities[battlerAtk] == ABILITY_SCRAPPY || aiData->abilities[battlerAtk] == ABILITY_MINDS_EYE)
@ -4254,10 +4258,13 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(GOOD_EFFECT); // Partner might use pledge move
break;
case EFFECT_TRICK_ROOM:
if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef))
ADJUST_SCORE(GOOD_EFFECT);
else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) >= GetBattlerSideSpeedAverage(battlerDef))
ADJUST_SCORE(GOOD_EFFECT);
if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS))
{
if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef))
ADJUST_SCORE(GOOD_EFFECT);
else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) >= GetBattlerSideSpeedAverage(battlerDef))
ADJUST_SCORE(GOOD_EFFECT);
}
break;
case EFFECT_MAGIC_ROOM:
ADJUST_SCORE(WEAK_EFFECT);
@ -4505,7 +4512,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score);
}
break;
case MOVE_EFFECT_RAPIDSPIN:
case MOVE_EFFECT_RAPID_SPIN:
if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0)
|| (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED))
ADJUST_SCORE(GOOD_EFFECT);
@ -4638,7 +4645,13 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
break;
case MOVE_EFFECT_STEALTH_ROCK:
case MOVE_EFFECT_SPIKES:
score += AI_ShouldSetUpHazards(battlerAtk, battlerDef, aiData);
if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, aiData));
{
if (gDisableStructs[battlerAtk].isFirstTurn)
ADJUST_SCORE(BEST_EFFECT);
else
ADJUST_SCORE(DECENT_EFFECT);
}
break;
case MOVE_EFFECT_FEINT:
if (gMovesInfo[predictedMove].effect == EFFECT_PROTECT)
@ -4654,7 +4667,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
}
break;
case MOVE_EFFECT_WRAP:
if (!HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPIDSPIN) && ShouldTrap(battlerAtk, battlerDef, move))
if (!HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) && ShouldTrap(battlerAtk, battlerDef, move))
ADJUST_SCORE(BEST_EFFECT);
break;
}
@ -5124,6 +5137,96 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
return score;
}
static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
{
u32 moveEffect = gMovesInfo[move].effect;
if (gMovesInfo[move].category != DAMAGE_CATEGORY_STATUS || gMovesInfo[AI_DATA->partnerMove].effect == moveEffect)
return score;
switch (moveEffect)
{
case EFFECT_TAILWIND:
if (!gSideTimers[GetBattlerSide(battlerAtk)].tailwindTimer && !(gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_TRICK_ROOM:
if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && !HasMoveEffect(battlerDef, EFFECT_TRICK_ROOM))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_MAGIC_ROOM:
if (!(gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) && !HasMoveEffect(battlerDef, EFFECT_MAGIC_ROOM))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_WONDER_ROOM:
if (!(gFieldStatuses & STATUS_FIELD_WONDER_ROOM) && !HasMoveEffect(battlerDef, EFFECT_WONDER_ROOM))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_GRAVITY:
if (!(gFieldStatuses & STATUS_FIELD_GRAVITY))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_SAFEGUARD:
if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_SAFEGUARD))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_MIST:
if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_LIGHT_SCREEN:
case EFFECT_REFLECT:
case EFFECT_AURORA_VEIL:
if (ShouldSetScreen(battlerAtk, battlerDef, moveEffect))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_SPIKES:
case EFFECT_STEALTH_ROCK:
case EFFECT_STICKY_WEB:
case EFFECT_TOXIC_SPIKES:
if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, AI_DATA))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_GRASSY_TERRAIN:
if (!(gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_ELECTRIC_TERRAIN:
if (!(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_PSYCHIC_TERRAIN:
if (!(gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_MISTY_TERRAIN:
if (!(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_SANDSTORM:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_SANDSTORM | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_SUNNY_DAY:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_SUN | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_RAIN_DANCE:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_RAIN | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_HAIL:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_HAIL | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_SNOWSCAPE:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_SNOW | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
}
return score;
}
static void AI_Flee(void)
{
AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK);

View file

@ -2860,6 +2860,10 @@ bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent)
bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect)
{
u32 atkSide = GetBattlerSide(battlerAtk);
if (HasMoveEffect(battlerDef, EFFECT_BRICK_BREAK)) // Don't waste a turn if screens will be broken
return FALSE;
switch (moveEffect)
{
case EFFECT_AURORA_VEIL:
@ -3587,10 +3591,13 @@ bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef)
}
//TODO - track entire opponent party data to determine hazard effectiveness
s32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData)
bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData)
{
if (aiData->abilities[battlerDef] == ABILITY_MAGIC_BOUNCE || CountUsablePartyMons(battlerDef) == 0)
return 0;
if (aiData->abilities[battlerDef] == ABILITY_MAGIC_BOUNCE
|| CountUsablePartyMons(battlerDef) == 0
|| HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN)
|| HasMoveEffect(battlerDef, EFFECT_DEFOG))
return FALSE;
return 2 * gDisableStructs[battlerAtk].isFirstTurn;
return TRUE;
}

View file

@ -3451,7 +3451,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
gBattlescriptCurrInstr = BattleScript_AllStatsUp;
}
break;
case MOVE_EFFECT_RAPIDSPIN:
case MOVE_EFFECT_RAPID_SPIN:
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_RapidSpinAway;
break;

View file

@ -942,7 +942,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3)
// Various cases to add/remove points
if (gMovesInfo[arg2].recoil > 0)
baseFromEffect++; // Recoil moves
if (MoveHasMoveEffect(arg2, MOVE_EFFECT_RAPIDSPIN))
if (MoveHasMoveEffect(arg2, MOVE_EFFECT_RAPID_SPIN))
baseFromEffect++;
if (MoveHasMoveEffect(arg2, MOVE_EFFECT_SP_ATK_TWO_DOWN) || MoveHasMoveEffect(arg2, MOVE_EFFECT_ATK_DEF_DOWN))
baseFromEffect += 2; // Overheat, Superpower, etc.

View file

@ -5639,7 +5639,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.category = DAMAGE_CATEGORY_PHYSICAL,
.makesContact = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_RAPIDSPIN,
.moveEffect = MOVE_EFFECT_RAPID_SPIN,
.self = TRUE,
}
#if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8
@ -18934,7 +18934,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.sheerForceBoost = TRUE,
.makesContact = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_RAPIDSPIN,
.moveEffect = MOVE_EFFECT_RAPID_SPIN,
.self = TRUE,
},
{

View file

@ -94,7 +94,7 @@ SINGLE_BATTLE_TEST("Shield Dust does not block self-targeting effects, primary o
GIVEN {
ASSUME(MoveHasMoveEffectSelf(MOVE_POWER_UP_PUNCH, MOVE_EFFECT_ATK_PLUS_1) == TRUE);
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPIDSPIN) == TRUE);
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(MoveHasMoveEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN) == TRUE);
ASSUME(MoveHasMoveEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE);
PLAYER(SPECIES_WOBBUFFET);

View file

@ -179,7 +179,6 @@ AI_SINGLE_BATTLE_TEST("AI chooses moves with secondary effect that have a 100% c
PARAMETRIZE { ability = ABILITY_SERENE_GRACE; }
GIVEN {
AI_LOG;
ASSUME(MoveHasMoveEffectWithChance(MOVE_SHADOW_BALL, MOVE_EFFECT_SP_DEF_MINUS_1, 20));
ASSUME(MoveHasMoveEffectWithChance(MOVE_OCTAZOOKA, MOVE_EFFECT_ACC_MINUS_1, 50));
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);

View file

@ -0,0 +1,54 @@
#include "global.h"
#include "test/battle.h"
#include "battle_ai_util.h"
AI_SINGLE_BATTLE_TEST("AI prefers to set up a powerful Status over fainting a target")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_TRICK_ROOM].effect == EFFECT_TRICK_ROOM);
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_POWERFUL_STATUS);
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_TRICK_ROOM, MOVE_TACKLE); }
} WHEN {
TURN { EXPECT_MOVE(opponent, MOVE_TRICK_ROOM); }
TURN { EXPECT_MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); }
} SCENE {
MESSAGE("Wobbuffet fainted!");
}
}
AI_SINGLE_BATTLE_TEST("AI will try to do damage on target instead of setting up hazards if target has a way to remove them")
{
GIVEN {
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].effect == EFFECT_STEALTH_ROCK);
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_POWERFUL_STATUS | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_WOBBUFFET) { HP(1); Moves(MOVE_RAPID_SPIN, MOVE_DEFOG, MOVE_CELEBRATE); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_GLIGAR) { Moves(MOVE_STEALTH_ROCK, MOVE_TACKLE); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { EXPECT_MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); }
} SCENE {
MESSAGE("Wobbuffet fainted!");
}
}
AI_SINGLE_BATTLE_TEST("AI will not set up Rain if it is already raining")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_RAIN_DANCE].effect == EFFECT_RAIN_DANCE);
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_POWERFUL_STATUS);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_RAIN_DANCE, MOVE_TACKLE); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { EXPECT_MOVE(opponent, MOVE_RAIN_DANCE); }
TURN { EXPECT_MOVE(opponent, MOVE_TACKLE); }
}
}

View file

@ -3,11 +3,11 @@
ASSUMPTIONS
{
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPIDSPIN) == TRUE);
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
#if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_SPD_PLUS_1) == TRUE);
#endif
ASSUME(MoveHasMoveEffectSelf(MOVE_MORTAL_SPIN, MOVE_EFFECT_RAPIDSPIN) == TRUE);
ASSUME(MoveHasMoveEffectSelf(MOVE_MORTAL_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(MoveHasMoveEffect(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON) == TRUE);
}