mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-27 04:04:17 +01:00
revert to CheckViability and stat change effect viabilities
This commit is contained in:
parent
1ae57f26a3
commit
f21b0140b9
@ -7,6 +7,7 @@
|
||||
|
||||
#define FOE(battler) ((battler ^ BIT_SIDE) & BIT_SIDE)
|
||||
|
||||
bool32 AI_RandLessThan(u8 val);
|
||||
void RecordLastUsedMoveByTarget(void);
|
||||
bool32 IsBattlerAIControlled(u32 battlerId);
|
||||
void ClearBattlerMoveHistory(u8 battlerId);
|
||||
@ -61,19 +62,20 @@ bool32 AreBattlersStatsMaxed(u8 battler);
|
||||
bool32 BattlerHasAnyStatRaised(u8 battlerId);
|
||||
u32 CountPositiveStatStages(u8 battlerId);
|
||||
u32 CountNegativeStatStages(u8 battlerId);
|
||||
bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex);
|
||||
bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex);
|
||||
bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex);
|
||||
bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex);
|
||||
bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex);
|
||||
bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex);
|
||||
bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex);
|
||||
bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility);
|
||||
bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility);
|
||||
bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility);
|
||||
bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility);
|
||||
bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility);
|
||||
bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility);
|
||||
bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility);
|
||||
|
||||
// move checks
|
||||
bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect);
|
||||
bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split);
|
||||
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef);
|
||||
u8 GetMoveDamageResult(u16 move);
|
||||
u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef);
|
||||
u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
|
||||
u8 AI_GetMoveEffectiveness(u16 move);
|
||||
u16 *GetMovesArray(u32 battler);
|
||||
|
@ -38,7 +38,7 @@
|
||||
// AI Flags. Most run specific functions to update score, new flags are used for internal logic in other scripts
|
||||
#define AI_FLAG_CHECK_BAD_MOVE (1 << 0)
|
||||
#define AI_FLAG_TRY_TO_FAINT (1 << 1)
|
||||
#define AI_FLAG_CHECK_GOOD_MOVE (1 << 2) // was AI_SCRIPT_CHECK_VIABILITY
|
||||
#define AI_FLAG_CHECK_VIABILITY (1 << 2)
|
||||
#define AI_FLAG_SETUP_FIRST_TURN (1 << 3)
|
||||
#define AI_FLAG_RISKY (1 << 4)
|
||||
#define AI_FLAG_PREFER_STRONGEST_MOVE (1 << 5)
|
||||
|
@ -48,7 +48,7 @@ EWRAM_DATA u8 sBattler_AI = 0;
|
||||
// const rom data
|
||||
static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score);
|
||||
static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score);
|
||||
static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score);
|
||||
static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score);
|
||||
static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score);
|
||||
static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score);
|
||||
static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score);
|
||||
@ -63,7 +63,7 @@ static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) =
|
||||
{
|
||||
[0] = AI_CheckBadMove, // AI_FLAG_CHECK_BAD_MOVE
|
||||
[1] = AI_TryToFaint, // AI_FLAG_TRY_TO_FAINT
|
||||
[2] = AI_CheckGoodMove, // AI_FLAG_CHECK_GOOD_MOVE
|
||||
[2] = AI_CheckViability, // AI_FLAG_CHECK_VIABILITY
|
||||
[3] = AI_SetupFirstTurn, // AI_FLAG_SETUP_FIRST_TURN
|
||||
[4] = AI_Risky, // AI_FLAG_RISKY
|
||||
[5] = AI_PreferStrongestMove, // AI_FLAG_PREFER_STRONGEST_MOVE
|
||||
@ -136,7 +136,7 @@ void BattleAI_SetupFlags(void)
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_FACTORY)
|
||||
AI_THINKING_STRUCT->aiFlags = GetAiScriptsInBattleFactory();
|
||||
else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE))
|
||||
AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_TRY_TO_FAINT;
|
||||
AI_THINKING_STRUCT->aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
||||
AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags | gTrainers[gTrainerBattleOpponent_B].aiFlags;
|
||||
else
|
||||
@ -278,13 +278,13 @@ static u8 ChooseMoveOrAction_Singles(void)
|
||||
&& !(gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
|
||||
&& !(gStatuses3[gActiveBattler] & STATUS3_ROOTED)
|
||||
&& !(gBattleTypeFlags & (BATTLE_TYPE_ARENA | BATTLE_TYPE_PALACE))
|
||||
&& AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_GOOD_MOVE | AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_PREFER_BATON_PASS))
|
||||
&& AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY | AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_PREFER_BATON_PASS))
|
||||
{
|
||||
// Consider switching if all moves are worthless to use.
|
||||
if (GetTotalBaseStat(gBattleMons[sBattler_AI].species) >= 310 // Mon is not weak.
|
||||
&& gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2)
|
||||
{
|
||||
s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_GOOD_MOVE) ? 95 : 93;
|
||||
s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_FLAG_CHECK_VIABILITY) ? 95 : 93;
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->score[i] > cap)
|
||||
@ -2094,7 +2094,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetBattlerSideSpeedAverage(battlerAtk) > GetBattlerSideSpeedAverage(battlerDef)) // Attacker side faster than target side
|
||||
if (GetBattlerSideSpeedAverage(battlerAtk) >= GetBattlerSideSpeedAverage(battlerDef)) // Attacker side faster than target side
|
||||
score -= 10; // Keep the Trick Room down
|
||||
}
|
||||
break;
|
||||
@ -2393,27 +2393,6 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
break;*/
|
||||
} // move effect checks
|
||||
|
||||
// substitute check
|
||||
if (IS_MOVE_STATUS(move) && DoesSubstituteBlockMove(battlerAtk, battlerDef, move))
|
||||
score -= 10;
|
||||
|
||||
// damage check
|
||||
if (!IS_MOVE_STATUS(move))
|
||||
{
|
||||
if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED))
|
||||
score -= 15;
|
||||
|
||||
if (effectiveness < AI_EFFECTIVENESS_x1 || GetMoveDamageResult(move) <= MOVE_POWER_WEAK)
|
||||
score -= 4;
|
||||
}
|
||||
|
||||
// helping hand check
|
||||
if (isDoubleBattle
|
||||
&& AI_DATA->partnerMove != MOVE_NONE
|
||||
&& gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_HELPING_HAND
|
||||
&& IS_MOVE_STATUS(move))
|
||||
score -= 10; // Don't use a status move if partner helping
|
||||
|
||||
if (score < 0)
|
||||
score = 0;
|
||||
|
||||
@ -2721,53 +2700,68 @@ static s16 AI_TryOnAlly(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
RETURN_SCORE_MINUS(30); // otherwise, we do not want to target our ally
|
||||
}
|
||||
|
||||
// AI_FLAG_CHECK_GOOD_MOVE - increases move scores
|
||||
static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
// AI_FLAG_CHECK_VIABILITY - a weird mix of increasing and decreasing scores
|
||||
static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
{
|
||||
// move data
|
||||
u16 moveEffect = gBattleMoves[move].effect;
|
||||
u8 effectiveness = AI_GetMoveEffectiveness(move);
|
||||
u8 typeEffectiveness = AI_GetTypeEffectiveness(move, battlerAtk, battlerDef);
|
||||
u8 atkPriority = GetMovePriority(battlerAtk, move);
|
||||
u16 predictedMove = gLastMoves[battlerDef]; //for now
|
||||
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
|
||||
u32 i;
|
||||
u8 atkHpPercent = GetHealthPercentage(battlerAtk);
|
||||
u8 defHpPercent = GetHealthPercentage(battlerDef);
|
||||
|
||||
// Targeting partner, check benefits of doing that instead
|
||||
if (IsTargetingPartner(battlerAtk, battlerDef))
|
||||
return score;
|
||||
|
||||
// check move results
|
||||
if (gMoveResultFlags & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED))
|
||||
return 0; // don't use ineffective moves
|
||||
|
||||
// if target goes first and can kill us, lets try to use a priority move to at least do something
|
||||
if (!(gBattleMons[battlerDef].status2 & (STATUS2_RECHARGE | STATUS2_BIDE))
|
||||
&& CanTargetFaintAi(battlerAtk, battlerDef)
|
||||
&& GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 // opponent should go first
|
||||
&& atkPriority > 0)
|
||||
score += 5;
|
||||
|
||||
// if target is evasive (or we have low accuracy)) and this move always hits, boost its score
|
||||
// check always hits
|
||||
if (!IS_MOVE_STATUS(move) && gBattleMoves[move].accuracy == 0)
|
||||
{
|
||||
if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 8)
|
||||
if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 10 || gBattleMons[battlerAtk].statStages[STAT_ACC] <= 2)
|
||||
score++;
|
||||
else if (gBattleMons[battlerAtk].statStages[STAT_ACC] <= 4)
|
||||
if (AI_RandLessThan(100) && (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 8 || gBattleMons[battlerAtk].statStages[STAT_ACC] <= 4))
|
||||
score++;
|
||||
}
|
||||
|
||||
// prefer good damaging moves
|
||||
if (GetMoveDamageResult(move) == MOVE_POWER_BEST)
|
||||
score += 2;
|
||||
// check high crit
|
||||
if (TestMoveFlags(move, FLAG_HIGH_CRIT) && effectiveness >= AI_EFFECTIVENESS_x2 && AI_RandLessThan(128))
|
||||
score++;
|
||||
|
||||
// check already dead
|
||||
if (!IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility)
|
||||
&& CanTargetFaintAi(battlerAtk, battlerDef)
|
||||
&& GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // opponent should go first
|
||||
{
|
||||
if (atkPriority > 0)
|
||||
score++;
|
||||
else
|
||||
score--;
|
||||
}
|
||||
|
||||
// check damage
|
||||
if (gBattleMoves[move].power != 0 && GetMoveDamageResult(move) == MOVE_POWER_WEAK)
|
||||
score--;
|
||||
|
||||
/*if (CountUsablePartyMons(battlerAtk) != 0
|
||||
&& GetMoveDamageResult(move) != 0 && !HasMoveWithSplit(battlerAtk, SPLIT_STATUS)
|
||||
&& GetCurrDamageHpPercent(battlerAtk, battlerDef) < 30)
|
||||
{
|
||||
if (GetCurrDamageHpPercent(battlerAtk, battlerDef) > 20)
|
||||
score--;
|
||||
else if (GetMoveDamageResult(move) == MOVE_POWER_BEST)
|
||||
score -= 2;
|
||||
else
|
||||
score -= 3;
|
||||
}*/
|
||||
|
||||
// check status move preference
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_PREFER_STATUS_MOVES && IS_MOVE_STATUS(move))
|
||||
score++;
|
||||
|
||||
// check high crit
|
||||
if (TestMoveFlags(move, FLAG_HIGH_CRIT) && effectiveness >= AI_EFFECTIVENESS_x2)
|
||||
score++;
|
||||
|
||||
// check thawing moves
|
||||
if ((gBattleMons[battlerAtk].status1 & STATUS1_FREEZE) && IsThawingMove(move))
|
||||
score += (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) ? 20 : 10;
|
||||
@ -2783,71 +2777,257 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
score += 8; // prioritize killing target for stat boost
|
||||
}
|
||||
break;
|
||||
} // ability checks
|
||||
case ABILITY_MAGIC_GUARD:
|
||||
switch (moveEffect)
|
||||
{
|
||||
case EFFECT_POISON:
|
||||
case EFFECT_WILL_O_WISP:
|
||||
case EFFECT_TOXIC:
|
||||
case EFFECT_LEECH_SEED:
|
||||
score -= 5;
|
||||
break;
|
||||
case EFFECT_CURSE:
|
||||
if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST))
|
||||
score -= 5;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} // ability checks
|
||||
|
||||
// move effect checks
|
||||
switch (moveEffect)
|
||||
{
|
||||
|
||||
case EFFECT_HIT:
|
||||
break;
|
||||
case EFFECT_SLEEP:
|
||||
case EFFECT_YAWN:
|
||||
IncreaseSleepScore(battlerAtk, battlerDef, move, &score);
|
||||
if (AI_RandLessThan(128))
|
||||
IncreaseSleepScore(battlerAtk, battlerDef, move, &score);
|
||||
break;
|
||||
case EFFECT_ABSORB:
|
||||
if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT)
|
||||
score++;
|
||||
if (typeEffectiveness <= AI_EFFECTIVENESS_x0_5 && AI_RandLessThan(50))
|
||||
score -= 3;
|
||||
break;
|
||||
case EFFECT_EXPLOSION:
|
||||
case EFFECT_MEMENTO:
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7)
|
||||
{
|
||||
if (atkHpPercent < 50 && AI_RandLessThan(128))
|
||||
score++;
|
||||
}
|
||||
break;
|
||||
case EFFECT_MIRROR_MOVE:
|
||||
if (predictedMove != MOVE_NONE)
|
||||
return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score);
|
||||
break;
|
||||
// stat raising effects
|
||||
case EFFECT_ATTACK_UP:
|
||||
case EFFECT_ATTACK_UP_2:
|
||||
if (MovesWithSplitUnusable(battlerAtk, battlerDef, SPLIT_PHYSICAL))
|
||||
{
|
||||
score -= 8;
|
||||
break;
|
||||
}
|
||||
else if (gBattleMons[battlerAtk].statStages[STAT_ATK] < 9)
|
||||
{
|
||||
if (atkHpPercent > 90 && AI_RandLessThan(128))
|
||||
{
|
||||
score += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AI_RandLessThan(100))
|
||||
{
|
||||
score--;
|
||||
}
|
||||
break;
|
||||
case EFFECT_DEFENSE_UP:
|
||||
case EFFECT_DEFENSE_UP_2:
|
||||
case EFFECT_DEFENSE_UP_3:
|
||||
if (!HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL))
|
||||
score -= 2;
|
||||
if (atkHpPercent > 90 && AI_RandLessThan(128))
|
||||
score += 2;
|
||||
else if (atkHpPercent > 70 && AI_RandLessThan(200))
|
||||
break;
|
||||
else if (atkHpPercent < 40)
|
||||
score -= 2;
|
||||
break;
|
||||
case EFFECT_SPEED_UP:
|
||||
case EFFECT_SPEED_UP_2:
|
||||
if (IsAiFaster(AI_CHECK_SLOWER))
|
||||
{
|
||||
if (!AI_RandLessThan(70))
|
||||
score += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
score -= 3;
|
||||
}
|
||||
break;
|
||||
case EFFECT_SPECIAL_ATTACK_UP:
|
||||
case EFFECT_SPECIAL_ATTACK_UP_2:
|
||||
case EFFECT_SPECIAL_ATTACK_UP_3:
|
||||
if (MovesWithSplitUnusable(battlerAtk, battlerDef, SPLIT_SPECIAL))
|
||||
{
|
||||
score -= 8;
|
||||
break;
|
||||
}
|
||||
else if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < 9)
|
||||
{
|
||||
if (atkHpPercent > 90 && AI_RandLessThan(128))
|
||||
{
|
||||
score += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AI_RandLessThan(100))
|
||||
{
|
||||
score--;
|
||||
}
|
||||
break;
|
||||
case EFFECT_SPECIAL_DEFENSE_UP:
|
||||
case EFFECT_SPECIAL_DEFENSE_UP_2:
|
||||
if (!HasMoveWithSplit(battlerDef, SPLIT_SPECIAL))
|
||||
score -= 2;
|
||||
if (atkHpPercent > 90 && AI_RandLessThan(128))
|
||||
score += 2;
|
||||
else if (GetHealthPercentage(battlerAtk) > 70 && AI_RandLessThan(200))
|
||||
break;
|
||||
else if (GetHealthPercentage(battlerAtk) < 40)
|
||||
score -= 2;
|
||||
break;
|
||||
case EFFECT_ACCURACY_UP:
|
||||
case EFFECT_ACCURACY_UP_2:
|
||||
if (gBattleMons[battlerAtk].statStages[STAT_ACC] >= 9 && !AI_RandLessThan(50))
|
||||
score -= 2;
|
||||
else if (atkHpPercent <= 70)
|
||||
score -= 2;
|
||||
else
|
||||
score++;
|
||||
break;
|
||||
case EFFECT_EVASION_UP:
|
||||
case EFFECT_EVASION_UP_2:
|
||||
if (atkHpPercent > 90 && !AI_RandLessThan(100))
|
||||
score += 3;
|
||||
if (gBattleMons[battlerAtk].statStages[STAT_EVASION] > 9 && AI_RandLessThan(128))
|
||||
score--;
|
||||
if ((gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) && atkHpPercent >= 50 && !AI_RandLessThan(80))
|
||||
score += 3;
|
||||
if (gStatuses3[battlerDef] & STATUS3_LEECHSEED && !AI_RandLessThan(70))
|
||||
score += 3;
|
||||
if (gStatuses3[battlerAtk] & STATUS3_ROOTED && AI_RandLessThan(128))
|
||||
score += 2;
|
||||
if (gBattleMons[battlerDef].status2 & STATUS2_CURSED && !AI_RandLessThan(70))
|
||||
score += 3;
|
||||
if (atkHpPercent < 70 || gBattleMons[battlerAtk].statStages[STAT_EVASION] == DEFAULT_STAT_STAGE)
|
||||
break;
|
||||
else if (atkHpPercent < 40 || defHpPercent < 40)
|
||||
score -= 2;
|
||||
else if (!AI_RandLessThan(70))
|
||||
score -= 2;
|
||||
break;
|
||||
// stat lowering effects
|
||||
case EFFECT_ATTACK_DOWN:
|
||||
case EFFECT_ATTACK_DOWN_2:
|
||||
if (!ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility))
|
||||
score -= 2;
|
||||
if (gBattleMons[battlerDef].statStages[STAT_ATK] < DEFAULT_STAT_STAGE)
|
||||
score--;
|
||||
else if (atkHpPercent <= 90)
|
||||
score--;
|
||||
if (gBattleMons[battlerDef].statStages[STAT_ATK] > 3 && !AI_RandLessThan(50))
|
||||
score -= 2;
|
||||
else if (defHpPercent < 70)
|
||||
score -= 2;
|
||||
break;
|
||||
case EFFECT_DEFENSE_DOWN:
|
||||
case EFFECT_DEFENSE_DOWN_2:
|
||||
if (!ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility))
|
||||
score -= 2;
|
||||
if ((atkHpPercent < 70 && !AI_RandLessThan(50)) || (gBattleMons[battlerDef].statStages[STAT_DEF] <= 3 && !AI_RandLessThan(50)))
|
||||
score -= 2;
|
||||
if (defHpPercent <= 70)
|
||||
score -= 2;
|
||||
break;
|
||||
case EFFECT_SPEED_DOWN:
|
||||
case EFFECT_SPEED_DOWN_2:
|
||||
if (IsAiFaster(AI_CHECK_FASTER))
|
||||
score -= 3;
|
||||
else if (!AI_RandLessThan(70))
|
||||
score += 2;
|
||||
break;
|
||||
case EFFECT_SPECIAL_ATTACK_DOWN:
|
||||
case EFFECT_SPECIAL_ATTACK_DOWN_2:
|
||||
if (!ShouldLowerSpAtk(battlerAtk, battlerDef, AI_DATA->defAbility))
|
||||
score -= 2;
|
||||
if (gBattleMons[battlerDef].statStages[STAT_SPATK] < DEFAULT_STAT_STAGE)
|
||||
score--;
|
||||
else if (atkHpPercent <= 90)
|
||||
score--;
|
||||
if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 3 && !AI_RandLessThan(50))
|
||||
score -= 2;
|
||||
else if (defHpPercent < 70)
|
||||
score -= 2;
|
||||
break;
|
||||
case EFFECT_SPECIAL_DEFENSE_DOWN:
|
||||
case EFFECT_SPECIAL_DEFENSE_DOWN_2:
|
||||
if (!ShouldLowerSpDef(battlerAtk, battlerDef, AI_DATA->defAbility))
|
||||
score -= 2;
|
||||
if ((atkHpPercent < 70 && !AI_RandLessThan(50))
|
||||
|| (gBattleMons[battlerDef].statStages[STAT_SPDEF] <= 3 && !AI_RandLessThan(50)))
|
||||
score -= 2;
|
||||
if (defHpPercent <= 70)
|
||||
score -= 2;
|
||||
break;
|
||||
case EFFECT_ACCURACY_DOWN:
|
||||
case EFFECT_ACCURACY_DOWN_2:
|
||||
if (ShouldLowerAccuracy(battlerAtk, battlerDef, AI_DATA->defAbility))
|
||||
score -= 2;
|
||||
if ((atkHpPercent < 70 || defHpPercent < 70) && AI_RandLessThan(100))
|
||||
score--;
|
||||
if (gBattleMons[battlerDef].statStages[STAT_ACC] <= 4 && !AI_RandLessThan(80))
|
||||
score -= 2;
|
||||
if (gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY && !AI_RandLessThan(70))
|
||||
score += 2;
|
||||
if (gStatuses3[battlerDef] & STATUS3_LEECHSEED && !AI_RandLessThan(70))
|
||||
score += 2;
|
||||
if (gStatuses3[battlerDef] & STATUS3_ROOTED && AI_RandLessThan(128))
|
||||
score++;
|
||||
if (gBattleMons[battlerDef].status2 & STATUS2_CURSED && !AI_RandLessThan(70))
|
||||
score += 2;
|
||||
if (atkHpPercent > 70 || gBattleMons[battlerDef].statStages[STAT_ACC] < DEFAULT_STAT_STAGE)
|
||||
break;
|
||||
else if (atkHpPercent < 40 || defHpPercent < 40 || !AI_RandLessThan(70))
|
||||
score -= 2;
|
||||
break;
|
||||
case EFFECT_EVASION_DOWN:
|
||||
case EFFECT_EVASION_DOWN_2:
|
||||
if (!ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility))
|
||||
score -= 2;
|
||||
if ((atkHpPercent < 70 || gBattleMons[battlerDef].statStages[STAT_EVASION] <= 3) && !AI_RandLessThan(50))
|
||||
score -= 2;
|
||||
if (defHpPercent <= 70)
|
||||
score -= 2;
|
||||
if (gBattleMons[battlerAtk].statStages[STAT_ACC] < DEFAULT_STAT_STAGE)
|
||||
score++;
|
||||
if (gBattleMons[battlerDef].statStages[STAT_EVASION] < 7 || AI_DATA->atkAbility == ABILITY_NO_GUARD)
|
||||
score -= 2;
|
||||
break;
|
||||
case EFFECT_BIDE:
|
||||
if (atkHpPercent < 90)
|
||||
score -= 2;
|
||||
break;
|
||||
case EFFECT_DREAM_EATER:
|
||||
if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP))
|
||||
break;
|
||||
score++; // if target is asleep, dream eater is a pretty good move even without draining
|
||||
// fallthrough
|
||||
case EFFECT_ABSORB:
|
||||
if (ShouldAbsorb(battlerAtk, battlerDef, move, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]))
|
||||
score += 2;
|
||||
if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT)
|
||||
score++;
|
||||
break;
|
||||
case EFFECT_EXPLOSION:
|
||||
case EFFECT_MEMENTO:
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7)
|
||||
{
|
||||
if (GetHealthPercentage(battlerAtk) < 50 && (Random() % 2))
|
||||
score++;
|
||||
}
|
||||
break;
|
||||
case EFFECT_MIRROR_MOVE:
|
||||
if (gLastMoves[battlerDef] != MOVE_NONE)
|
||||
return AI_CheckGoodMove(battlerAtk, battlerDef, gLastMoves[battlerDef], score);
|
||||
break;
|
||||
case EFFECT_ATTACK_UP:
|
||||
case EFFECT_ATTACK_UP_2:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score);
|
||||
break;
|
||||
case EFFECT_DEFENSE_UP:
|
||||
case EFFECT_DEFENSE_UP_2:
|
||||
case EFFECT_DEFENSE_UP_3:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_DEF, &score);
|
||||
break;
|
||||
case EFFECT_SPEED_UP:
|
||||
case EFFECT_SPEED_UP_2:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score);
|
||||
break;
|
||||
case EFFECT_SPECIAL_ATTACK_UP:
|
||||
case EFFECT_SPECIAL_ATTACK_UP_2:
|
||||
case EFFECT_SPECIAL_ATTACK_UP_3:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score);
|
||||
break;
|
||||
case EFFECT_SPECIAL_DEFENSE_UP:
|
||||
case EFFECT_SPECIAL_DEFENSE_UP_2:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score);
|
||||
break;
|
||||
case EFFECT_ACCURACY_UP:
|
||||
case EFFECT_ACCURACY_UP_2:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ACC, &score);
|
||||
break;
|
||||
case EFFECT_EVASION_UP:
|
||||
case EFFECT_EVASION_UP_2:
|
||||
case EFFECT_MINIMIZE:
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_EVASION, &score);
|
||||
break;
|
||||
case EFFECT_ACUPRESSURE:
|
||||
break;
|
||||
case EFFECT_ATTACK_ACCURACY_UP: // hone claws
|
||||
@ -2864,51 +3044,10 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
else if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL))
|
||||
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score);
|
||||
break;
|
||||
case EFFECT_ATTACK_DOWN:
|
||||
case EFFECT_ATTACK_DOWN_2:
|
||||
if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
score += 2;
|
||||
break;
|
||||
case EFFECT_DEFENSE_DOWN:
|
||||
case EFFECT_DEFENSE_DOWN_2:
|
||||
if (ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
score += 2;
|
||||
break;
|
||||
case EFFECT_SPEED_DOWN:
|
||||
case EFFECT_SPEED_DOWN_2:
|
||||
if (ShouldLowerSpeed(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
score += 3;
|
||||
break;
|
||||
case EFFECT_SPECIAL_ATTACK_DOWN:
|
||||
case EFFECT_SPECIAL_ATTACK_DOWN_2:
|
||||
if (ShouldLowerSpAtk(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
score += 2;
|
||||
break;
|
||||
case EFFECT_SPECIAL_DEFENSE_DOWN:
|
||||
case EFFECT_SPECIAL_DEFENSE_DOWN_2:
|
||||
if (ShouldLowerSpDef(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
score += 2;
|
||||
break;
|
||||
case EFFECT_ACCURACY_DOWN:
|
||||
case EFFECT_ACCURACY_DOWN_2:
|
||||
if (ShouldLowerAccuracy(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
score += 4;
|
||||
break;
|
||||
case EFFECT_EVASION_DOWN:
|
||||
case EFFECT_EVASION_DOWN_2:
|
||||
if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
{
|
||||
// kinda meh effect, so let's make sure we really want to
|
||||
if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 7
|
||||
|| HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect))
|
||||
score += 2; // encourage lowering evasion if they are evasive or we have a move with low accuracy
|
||||
else
|
||||
score++;
|
||||
}
|
||||
break;
|
||||
case EFFECT_HAZE:
|
||||
if (AnyStatIsRaised(AI_DATA->battlerAtkPartner)
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove))
|
||||
score -= 3;
|
||||
break;
|
||||
// fallthrough
|
||||
case EFFECT_ROAR:
|
||||
@ -2918,8 +3057,6 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
else
|
||||
score += min(CountPositiveStatStages(battlerDef), 4);
|
||||
break;
|
||||
case EFFECT_BIDE:
|
||||
break;
|
||||
case EFFECT_MULTI_HIT:
|
||||
case EFFECT_DOUBLE_HIT:
|
||||
case EFFECT_TRIPLE_KICK:
|
||||
@ -3057,13 +3194,12 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
score += 2;
|
||||
break;
|
||||
case EFFECT_SPEED_DOWN_HIT:
|
||||
if (ShouldLowerSpeed(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
{
|
||||
if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY)
|
||||
score += 4;
|
||||
else
|
||||
score += 2;
|
||||
}
|
||||
if (IsAiFaster(AI_CHECK_FASTER))
|
||||
score -= 2;
|
||||
else if (!AI_RandLessThan(70))
|
||||
score++;
|
||||
if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY)
|
||||
score++;
|
||||
break;
|
||||
case EFFECT_SUBSTITUTE:
|
||||
if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG)
|
||||
@ -3085,7 +3221,7 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0)
|
||||
{
|
||||
if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF)
|
||||
return AI_CheckGoodMove(battlerAtk, battlerDef, gLastMoves[battlerDef], score);
|
||||
return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score);
|
||||
}
|
||||
break;
|
||||
case EFFECT_LEECH_SEED:
|
||||
@ -3605,7 +3741,7 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
}
|
||||
|
||||
// check defog lowering evasion
|
||||
if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility))
|
||||
{
|
||||
if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 7
|
||||
|| HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect))
|
||||
@ -3639,7 +3775,7 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
}
|
||||
break;
|
||||
case EFFECT_NATURE_POWER:
|
||||
return AI_CheckGoodMove(battlerAtk, battlerDef, GetNaturePowerMove(), score);
|
||||
return AI_CheckViability(battlerAtk, battlerDef, GetNaturePowerMove(), score);
|
||||
case EFFECT_CHARGE:
|
||||
if (HasDamagingMoveOfType(battlerAtk, TYPE_ELECTRIC))
|
||||
score += 2;
|
||||
@ -3850,11 +3986,11 @@ static s16 AI_CheckGoodMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|
||||
break;
|
||||
case EFFECT_TICKLE:
|
||||
if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)
|
||||
&& AI_DATA->defAbility != ABILITY_CONTRARY && ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
&& AI_DATA->defAbility != ABILITY_CONTRARY && ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility))
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
else if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility, AI_THINKING_STRUCT->movesetIndex))
|
||||
else if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility))
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
|
@ -436,6 +436,13 @@ static const u16 sOtherMoveCallingMoves[] =
|
||||
};
|
||||
|
||||
// Functions
|
||||
bool32 AI_RandLessThan(u8 val)
|
||||
{
|
||||
if ((Random() % 0xFF) < val)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void RecordLastUsedMoveByTarget(void)
|
||||
{
|
||||
RecordKnownMove(gBattlerTarget, gLastMoves[gBattlerTarget]);
|
||||
@ -857,6 +864,13 @@ u8 GetMoveDamageResult(u16 move)
|
||||
return AI_THINKING_STRUCT->funcResult;
|
||||
}
|
||||
|
||||
u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef)
|
||||
{
|
||||
int bestDmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
|
||||
|
||||
return (bestDmg * 100) / gBattleMons[battlerDef].maxHP;
|
||||
}
|
||||
|
||||
u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
|
||||
{
|
||||
u8 damageVar;
|
||||
@ -1583,9 +1597,9 @@ u32 CountNegativeStatStages(u8 battlerId)
|
||||
return count;
|
||||
}
|
||||
|
||||
bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex)
|
||||
bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility)
|
||||
{
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0))
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4
|
||||
@ -1599,9 +1613,9 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIn
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex)
|
||||
bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility)
|
||||
{
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0))
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4
|
||||
@ -1615,9 +1629,9 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveI
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex)
|
||||
bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility)
|
||||
{
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0))
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (IsAiFaster(AI_CHECK_SLOWER)
|
||||
@ -1629,9 +1643,9 @@ bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveInd
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex)
|
||||
bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility)
|
||||
{
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0))
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4
|
||||
@ -1644,9 +1658,9 @@ bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveInd
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex)
|
||||
bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility)
|
||||
{
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0))
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4
|
||||
@ -1659,9 +1673,9 @@ bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveInd
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex)
|
||||
bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility)
|
||||
{
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0))
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (defAbility != ABILITY_CONTRARY
|
||||
@ -1673,9 +1687,9 @@ bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 move
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 moveIndex)
|
||||
bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility)
|
||||
{
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0))
|
||||
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE
|
||||
@ -3228,6 +3242,9 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
|
||||
if (AI_DATA->atkAbility == ABILITY_CONTRARY)
|
||||
return;
|
||||
|
||||
if (GetHealthPercentage(battlerAtk) < 80 && AI_RandLessThan(128))
|
||||
return;
|
||||
|
||||
switch (statId)
|
||||
{
|
||||
case STAT_ATK:
|
||||
@ -3304,16 +3321,16 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
|
||||
if (!HasDamagingMove(battlerDef))
|
||||
*score += 2;
|
||||
|
||||
if (HasMoveEffect(battlerAtk, EFFECT_PROTECT))
|
||||
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT))
|
||||
(*score)++; // stall tactic
|
||||
|
||||
if (HasMoveEffect(battlerAtk, EFFECT_VENOSHOCK)
|
||||
|| HasMoveEffect(battlerAtk, EFFECT_HEX)
|
||||
|| HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH)
|
||||
|| AI_DATA->atkAbility == ABILITY_MERCILESS)
|
||||
*score += 4;
|
||||
*(score) += 2;
|
||||
else
|
||||
*score += 2;
|
||||
*(score)++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3354,8 +3371,10 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
|
||||
void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
|
||||
{
|
||||
if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove))
|
||||
*score += 3;
|
||||
|
||||
*score += 2;
|
||||
else
|
||||
return;
|
||||
|
||||
if ((HasMoveEffect(battlerAtk, EFFECT_DREAM_EATER) || HasMoveEffect(battlerAtk, EFFECT_NIGHTMARE))
|
||||
&& !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK)))
|
||||
(*score)++;
|
||||
|
@ -850,13 +850,13 @@ u32 GetAiScriptsInBattleFactory(void)
|
||||
int challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7;
|
||||
|
||||
if (gTrainerBattleOpponent_A == TRAINER_FRONTIER_BRAIN)
|
||||
return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE;
|
||||
return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY;
|
||||
else if (challengeNum < 2)
|
||||
return 0;
|
||||
else if (challengeNum < 4)
|
||||
return AI_FLAG_CHECK_BAD_MOVE;
|
||||
else
|
||||
return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE;
|
||||
return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY;
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -897,7 +897,7 @@ void FillHillTrainersParties(void)
|
||||
// hill trainers.
|
||||
u32 GetTrainerHillAIFlags(void)
|
||||
{
|
||||
return (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE);
|
||||
return (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY);
|
||||
}
|
||||
|
||||
u8 GetTrainerEncounterMusicIdInTrainerHill(u16 trainerId)
|
||||
|
Loading…
Reference in New Issue
Block a user