Adds Powerful status move flag (#4125)
* Adds Powerful status move flag * fix flag * fixed final issues * review changes
This commit is contained in:
parent
7ab23cf426
commit
7694628296
13 changed files with 213 additions and 49 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
54
test/battle/ai_powerful_status.c
Normal file
54
test/battle/ai_powerful_status.c
Normal 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); }
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue