Stat stage related AI fixes (#4548)
* stat stage related AI fixes * add more ai fixes and 2 tests * use legal ability in tests * Fix test and remove mold breaker check * Use DoesBattlerIgnoreAbilityChecks
This commit is contained in:
parent
8de4ed5a7c
commit
f502ba2a69
@ -32,13 +32,13 @@
|
||||
#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
|
||||
// Temporary scores that are added together to determine a final score at the at of AI_CalcMoveEffectScore
|
||||
#define WEAK_EFFECT 1
|
||||
#define DECENT_EFFECT 2
|
||||
#define GOOD_EFFECT 4
|
||||
#define BEST_EFFECT 6
|
||||
|
||||
// AI_CalcMoveScore final score
|
||||
// AI_CalcMoveEffectScore final score
|
||||
#define NOT_GOOD_ENOUGH 0 // Not worth using over a damaging move
|
||||
#define GOOD_MOVE_EFFECTS 2 // Worth using over a damaging move
|
||||
#define PREFERRED_MOVE_EFFECTS 3 // Worth using over a damagin move and is better then DECENT_EFFECT
|
||||
|
||||
@ -179,6 +179,7 @@ bool32 SideHasMoveCategory(u32 battlerId, u32 category);
|
||||
|
||||
// score increases
|
||||
void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score);
|
||||
void IncreaseStatUpScoreContrary(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score);
|
||||
void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
|
||||
@ -3161,7 +3161,7 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId)
|
||||
return score;
|
||||
}
|
||||
|
||||
static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
// move data
|
||||
u32 moveEffect = gMovesInfo[move].effect;
|
||||
@ -3592,7 +3592,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
else
|
||||
ADJUST_SCORE(WEAK_EFFECT);
|
||||
}
|
||||
else if (aiData->abilities[battlerAtk] != ABILITY_CONTRARY)
|
||||
else
|
||||
{
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score);
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score);
|
||||
@ -4407,56 +4407,88 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
// Consider move effects that target self
|
||||
if (gMovesInfo[move].additionalEffects[i].self)
|
||||
{
|
||||
u32 oneStageStatId = STAT_CHANGE_ATK + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1;
|
||||
u32 twoStageStatId = STAT_CHANGE_ATK_2 + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1;
|
||||
u32 StageStatId;
|
||||
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
if (aiData->abilities[battlerAtk] != ABILITY_CONTRARY)
|
||||
{
|
||||
case MOVE_EFFECT_SPD_PLUS_2:
|
||||
case MOVE_EFFECT_SPD_PLUS_1:
|
||||
if (aiData->abilities[battlerAtk] != ABILITY_CONTRARY && !AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_DEF_PLUS_1:
|
||||
case MOVE_EFFECT_SPD_PLUS_1:
|
||||
case MOVE_EFFECT_SP_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_SP_DEF_PLUS_1:
|
||||
case MOVE_EFFECT_ACC_PLUS_1:
|
||||
case MOVE_EFFECT_EVS_PLUS_1:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, oneStageStatId, &score);
|
||||
StageStatId = STAT_CHANGE_ATK + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1;
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, StageStatId, &score);
|
||||
break;
|
||||
case MOVE_EFFECT_ATK_PLUS_2:
|
||||
case MOVE_EFFECT_DEF_PLUS_2:
|
||||
case MOVE_EFFECT_SPD_PLUS_2:
|
||||
case MOVE_EFFECT_SP_ATK_PLUS_2:
|
||||
case MOVE_EFFECT_SP_DEF_PLUS_2:
|
||||
case MOVE_EFFECT_ACC_PLUS_2:
|
||||
case MOVE_EFFECT_EVS_PLUS_2:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, twoStageStatId, &score);
|
||||
StageStatId = STAT_CHANGE_ATK_2 + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1;
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, StageStatId, &score);
|
||||
break;
|
||||
// Effects that lower stat(s) - only need to consider Contrary
|
||||
case MOVE_EFFECT_ATK_MINUS_1:
|
||||
case MOVE_EFFECT_DEF_MINUS_1:
|
||||
case MOVE_EFFECT_SPD_MINUS_1:
|
||||
case MOVE_EFFECT_SP_ATK_MINUS_1:
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_1:
|
||||
case MOVE_EFFECT_DEF_SPDEF_DOWN:
|
||||
case MOVE_EFFECT_ATK_DEF_DOWN:
|
||||
case MOVE_EFFECT_SP_ATK_TWO_DOWN:
|
||||
if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY)
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, oneStageStatId, &score);
|
||||
case MOVE_EFFECT_V_CREATE:
|
||||
if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY)
|
||||
{
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score);
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score);
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score);
|
||||
}
|
||||
case MOVE_EFFECT_ACC_PLUS_1:
|
||||
case MOVE_EFFECT_ACC_PLUS_2:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ACC, &score);
|
||||
break;
|
||||
case MOVE_EFFECT_EVS_PLUS_1:
|
||||
case MOVE_EFFECT_EVS_PLUS_2:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_EVASION, &score);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_ATK_MINUS_1:
|
||||
case MOVE_EFFECT_DEF_MINUS_1:
|
||||
case MOVE_EFFECT_SPD_MINUS_1:
|
||||
case MOVE_EFFECT_SP_ATK_MINUS_1:
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_1:
|
||||
StageStatId = STAT_CHANGE_ATK + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_1;
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, StageStatId, &score);
|
||||
break;
|
||||
case MOVE_EFFECT_ATK_MINUS_2:
|
||||
case MOVE_EFFECT_DEF_MINUS_2:
|
||||
case MOVE_EFFECT_SPD_MINUS_2:
|
||||
case MOVE_EFFECT_SP_ATK_MINUS_2:
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_2:
|
||||
StageStatId = STAT_CHANGE_ATK + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_2;
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, StageStatId, &score);
|
||||
break;
|
||||
case MOVE_EFFECT_ACC_MINUS_1:
|
||||
case MOVE_EFFECT_ACC_MINUS_2:
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_ACC, &score);
|
||||
break;
|
||||
case MOVE_EFFECT_EVS_MINUS_1:
|
||||
case MOVE_EFFECT_EVS_MINUS_2:
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_EVASION, &score);
|
||||
break;
|
||||
case MOVE_EFFECT_DEF_SPDEF_DOWN:
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score);
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score);
|
||||
break;
|
||||
case MOVE_EFFECT_ATK_DEF_DOWN:
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score);
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score);
|
||||
break;
|
||||
case MOVE_EFFECT_SP_ATK_TWO_DOWN:
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_SPATK_2, &score);
|
||||
break;
|
||||
case MOVE_EFFECT_V_CREATE:
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score);
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score);
|
||||
IncreaseStatUpScoreContrary(battlerAtk, battlerDef, STAT_CHANGE_SPDEF, &score);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // consider move effects that hinder the target
|
||||
@ -4639,8 +4671,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
||||
score += AI_CompareDamagingMoves(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex);
|
||||
}
|
||||
|
||||
// Calculates score based on effects of a move
|
||||
score += AI_CalcMoveScore(battlerAtk, battlerDef, move);
|
||||
score += AI_CalcMoveEffectScore(battlerAtk, battlerDef, move);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
@ -627,22 +627,35 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_ATK_PLUS_2:
|
||||
if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK))
|
||||
return TRUE;
|
||||
break;
|
||||
case MOVE_EFFECT_DEF_PLUS_2:
|
||||
case MOVE_EFFECT_DEF_PLUS_1:
|
||||
case MOVE_EFFECT_DEF_PLUS_2:
|
||||
if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_DEF))
|
||||
return TRUE;
|
||||
break;
|
||||
case MOVE_EFFECT_SPD_PLUS_1:
|
||||
case MOVE_EFFECT_SPD_PLUS_2:
|
||||
if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_SPEED))
|
||||
return TRUE;
|
||||
break;
|
||||
case MOVE_EFFECT_SP_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_SP_ATK_PLUS_2:
|
||||
if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_SPATK))
|
||||
return TRUE;
|
||||
break;
|
||||
case MOVE_EFFECT_EVS_PLUS_1:
|
||||
case MOVE_EFFECT_EVS_PLUS_2:
|
||||
if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_EVASION))
|
||||
return TRUE;
|
||||
break;
|
||||
case MOVE_EFFECT_ACC_PLUS_1:
|
||||
case MOVE_EFFECT_ACC_PLUS_2:
|
||||
if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ACC))
|
||||
return TRUE;
|
||||
break;
|
||||
case MOVE_EFFECT_ALL_STATS_UP:
|
||||
for (i = STAT_ATK; i <= NUM_STATS; i++)
|
||||
{
|
||||
@ -737,18 +750,45 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
|
||||
case MOVE_EFFECT_DEF_MINUS_1:
|
||||
case MOVE_EFFECT_SPD_MINUS_1:
|
||||
case MOVE_EFFECT_SP_ATK_MINUS_1:
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_1:
|
||||
case MOVE_EFFECT_EVS_MINUS_1:
|
||||
case MOVE_EFFECT_ACC_MINUS_1:
|
||||
case MOVE_EFFECT_ATK_MINUS_2:
|
||||
case MOVE_EFFECT_DEF_MINUS_2:
|
||||
case MOVE_EFFECT_SPD_MINUS_2:
|
||||
case MOVE_EFFECT_SP_ATK_MINUS_2:
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_2:
|
||||
case MOVE_EFFECT_EVS_MINUS_2:
|
||||
case MOVE_EFFECT_ACC_MINUS_2:
|
||||
case MOVE_EFFECT_SP_ATK_TWO_DOWN:
|
||||
case MOVE_EFFECT_V_CREATE:
|
||||
case MOVE_EFFECT_ATK_DEF_DOWN:
|
||||
case MOVE_EFFECT_DEF_SPDEF_DOWN:
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_1:
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_2:
|
||||
if ((gMovesInfo[move].additionalEffects[i].self && GetBattlerAbility(battlerAtk) != ABILITY_CONTRARY)
|
||||
|| (noOfHitsToKo != 1 && abilityDef == ABILITY_CONTRARY && !IsMoldBreakerTypeAbility(abilityAtk)))
|
||||
if ((gMovesInfo[move].additionalEffects[i].self && abilityAtk != ABILITY_CONTRARY)
|
||||
|| (noOfHitsToKo != 1 && abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(abilityAtk, move)))
|
||||
return TRUE;
|
||||
break;
|
||||
case MOVE_EFFECT_RECHARGE:
|
||||
return gMovesInfo[move].additionalEffects[i].self;
|
||||
case MOVE_EFFECT_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_DEF_PLUS_1:
|
||||
case MOVE_EFFECT_SPD_PLUS_1:
|
||||
case MOVE_EFFECT_SP_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_SP_DEF_PLUS_1:
|
||||
case MOVE_EFFECT_EVS_PLUS_1:
|
||||
case MOVE_EFFECT_ACC_PLUS_1:
|
||||
case MOVE_EFFECT_ATK_PLUS_2:
|
||||
case MOVE_EFFECT_DEF_PLUS_2:
|
||||
case MOVE_EFFECT_SPD_PLUS_2:
|
||||
case MOVE_EFFECT_SP_ATK_PLUS_2:
|
||||
case MOVE_EFFECT_SP_DEF_PLUS_2:
|
||||
case MOVE_EFFECT_EVS_PLUS_2:
|
||||
case MOVE_EFFECT_ACC_PLUS_2:
|
||||
case MOVE_EFFECT_ALL_STATS_UP:
|
||||
if ((gMovesInfo[move].additionalEffects[i].self && abilityAtk == ABILITY_CONTRARY)
|
||||
|| (noOfHitsToKo != 1 && !(abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(abilityAtk, move))))
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -3388,13 +3428,13 @@ bool32 IsRecycleEncouragedItem(u32 item)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score)
|
||||
static void IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score, bool32 considerContrary)
|
||||
{
|
||||
u32 noOfHitsToFaint = NoOfHitsForTargetToFaintAI(battlerDef, battlerAtk);
|
||||
u32 aiIsFaster = GetWhichBattlerFaster(battlerAtk, battlerDef, TRUE) == AI_IS_FASTER;
|
||||
u32 shouldSetUp = ((noOfHitsToFaint >= 2 && aiIsFaster) || (noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS);
|
||||
|
||||
if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY)
|
||||
if (considerContrary && AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY)
|
||||
return;
|
||||
|
||||
// Don't increase stat if AI is at +4
|
||||
@ -3488,6 +3528,16 @@ void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score)
|
||||
}
|
||||
}
|
||||
|
||||
void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score)
|
||||
{
|
||||
IncreaseStatUpScoreInternal(battlerAtk, battlerDef, statId, score, TRUE);
|
||||
}
|
||||
|
||||
void IncreaseStatUpScoreContrary(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score)
|
||||
{
|
||||
IncreaseStatUpScoreInternal(battlerAtk, battlerDef, statId, score, FALSE);
|
||||
}
|
||||
|
||||
void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
{
|
||||
if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
|
||||
@ -830,3 +830,55 @@ AI_SINGLE_BATTLE_TEST("AI will choose Surf over Thunderbolt and Ice Beam if the
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_SURF); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI will choose Scratch over Power-up Punch with Contrary")
|
||||
{
|
||||
u32 ability;
|
||||
|
||||
PARAMETRIZE {ability = ABILITY_SUCTION_CUPS; }
|
||||
PARAMETRIZE {ability = ABILITY_CONTRARY; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SCRATCH].power == 40);
|
||||
ASSUME(gMovesInfo[MOVE_SCRATCH].type == TYPE_NORMAL);
|
||||
ASSUME(gMovesInfo[MOVE_POWER_UP_PUNCH].power == 40);
|
||||
ASSUME(gMovesInfo[MOVE_POWER_UP_PUNCH].type == TYPE_FIGHTING);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[0] == TYPE_WATER);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[1] == TYPE_WATER);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_SQUIRTLE) { };
|
||||
OPPONENT(SPECIES_MALAMAR) { Ability(ability); Moves(MOVE_SCRATCH, MOVE_POWER_UP_PUNCH); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
if (ability != ABILITY_CONTRARY)
|
||||
EXPECT_MOVE(opponent, MOVE_POWER_UP_PUNCH);
|
||||
else
|
||||
EXPECT_MOVE(opponent, MOVE_SCRATCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI will choose Superpower over Outrage with Contrary")
|
||||
{
|
||||
u32 ability;
|
||||
|
||||
PARAMETRIZE {ability = ABILITY_SUCTION_CUPS; }
|
||||
PARAMETRIZE {ability = ABILITY_CONTRARY; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SUPERPOWER].power == 120);
|
||||
ASSUME(gMovesInfo[MOVE_SUPERPOWER].type == TYPE_FIGHTING);
|
||||
ASSUME(gMovesInfo[MOVE_OUTRAGE].power == 120);
|
||||
ASSUME(gMovesInfo[MOVE_OUTRAGE].type == TYPE_DRAGON);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[0] == TYPE_WATER);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[1] == TYPE_WATER);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_SQUIRTLE) { };
|
||||
OPPONENT(SPECIES_MALAMAR) { Ability(ability); Moves(MOVE_OUTRAGE, MOVE_SUPERPOWER); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
if (ability != ABILITY_CONTRARY)
|
||||
EXPECT_MOVE(opponent, MOVE_OUTRAGE);
|
||||
else
|
||||
EXPECT_MOVE(opponent, MOVE_SUPERPOWER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user