mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2025-03-19 12:08:34 +01:00
outline AI_CheckGoodMove
This commit is contained in:
parent
ac332d5e98
commit
916d0416e3
@ -7,9 +7,6 @@
|
|||||||
#define AI_CHOICE_WATCH 5
|
#define AI_CHOICE_WATCH 5
|
||||||
#define AI_CHOICE_SWITCH 7
|
#define AI_CHOICE_SWITCH 7
|
||||||
|
|
||||||
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef);
|
|
||||||
s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon);
|
|
||||||
u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
|
|
||||||
void BattleAI_SetupItems(void);
|
void BattleAI_SetupItems(void);
|
||||||
void BattleAI_SetupFlags(void);
|
void BattleAI_SetupFlags(void);
|
||||||
void BattleAI_SetupAIData(u8 defaultScoreMoves);
|
void BattleAI_SetupAIData(u8 defaultScoreMoves);
|
||||||
@ -17,12 +14,6 @@ u8 BattleAI_ChooseMoveOrAction(void);
|
|||||||
bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler);
|
bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler);
|
||||||
bool32 IsBattlerAIControlled(u32 battlerId);
|
bool32 IsBattlerAIControlled(u32 battlerId);
|
||||||
void ClearBattlerMoveHistory(u8 battlerId);
|
void ClearBattlerMoveHistory(u8 battlerId);
|
||||||
void RecordLastUsedMoveBy(u32 battlerId, u32 move);
|
|
||||||
void RecordKnownMove(u8 battlerId, u32 move);
|
|
||||||
void RecordAbilityBattle(u8 battlerId, u16 abilityId);
|
|
||||||
void ClearBattlerAbilityHistory(u8 battlerId);
|
|
||||||
void RecordItemEffectBattle(u8 battlerId, u8 itemEffect);
|
|
||||||
void ClearBattlerItemEffectHistory(u8 battlerId);
|
|
||||||
|
|
||||||
extern u8 sBattler_AI;
|
extern u8 sBattler_AI;
|
||||||
|
|
||||||
|
@ -24,14 +24,13 @@ u32 GetHealthPercentage(u8 battler);
|
|||||||
bool32 IsBattlerTrapped(u8 battler, bool8 switching);
|
bool32 IsBattlerTrapped(u8 battler, bool8 switching);
|
||||||
bool32 IsBattlerFaster(u8 battler);
|
bool32 IsBattlerFaster(u8 battler);
|
||||||
bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk);
|
bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk);
|
||||||
|
bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod);
|
||||||
s32 AI_GetAbility(u32 battlerId);
|
s32 AI_GetAbility(u32 battlerId);
|
||||||
u16 AI_GetHoldEffect(u32 battlerId);
|
u16 AI_GetHoldEffect(u32 battlerId);
|
||||||
u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move);
|
u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move);
|
||||||
bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move);
|
bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move);
|
||||||
bool32 AI_WeatherHasEffect(void);
|
bool32 AI_WeatherHasEffect(void);
|
||||||
bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index);
|
bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index);
|
||||||
s32 CountUsablePartyMons(u8 battlerId);
|
|
||||||
bool32 IsPartyFullyHealedExceptBattler(u8 battler);
|
|
||||||
bool32 AI_IsBattlerGrounded(u8 battlerId);
|
bool32 AI_IsBattlerGrounded(u8 battlerId);
|
||||||
bool32 BattlerHasDamagingMove(u8 battlerId);
|
bool32 BattlerHasDamagingMove(u8 battlerId);
|
||||||
bool32 BattlerHasSecondaryDamage(u8 battlerId);
|
bool32 BattlerHasSecondaryDamage(u8 battlerId);
|
||||||
@ -39,6 +38,7 @@ bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability);
|
|||||||
bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move);
|
bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move);
|
||||||
bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex);
|
bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex);
|
||||||
u16 GetBattlerSideSpeedAverage(u8 battler);
|
u16 GetBattlerSideSpeedAverage(u8 battler);
|
||||||
|
bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage);
|
||||||
|
|
||||||
// stat stage checks
|
// stat stage checks
|
||||||
bool32 AnyStatIsRaised(u8 battlerId);
|
bool32 AnyStatIsRaised(u8 battlerId);
|
||||||
@ -51,13 +51,15 @@ u32 CountNegativeStatStages(u8 battlerId);
|
|||||||
bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability);
|
bool32 BattlerShouldRaiseAttacks(u8 battlerId, u16 ability);
|
||||||
|
|
||||||
// move checks
|
// move checks
|
||||||
u8 GetMovePowerResult(u16 move);
|
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef);
|
||||||
|
u8 GetMoveDamageResult(u16 move);
|
||||||
u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
|
u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
|
||||||
u8 AI_GetMoveEffectiveness(u16 move);
|
u8 AI_GetMoveEffectiveness(u16 move);
|
||||||
u16 *GetMovesArray(u32 battler);
|
u16 *GetMovesArray(u32 battler);
|
||||||
bool32 IsConfusionMoveEffect(u16 moveEffect);
|
bool32 IsConfusionMoveEffect(u16 moveEffect);
|
||||||
bool32 HasMoveWithSplit(u32 battler, u32 split);
|
bool32 HasMoveWithSplit(u32 battler, u32 split);
|
||||||
bool32 HasMoveWithType(u32 battler, u8 type);
|
bool32 HasMoveWithType(u32 battler, u8 type);
|
||||||
|
bool32 HasMoveEffect(u32 battlerId, u16 moveEffect);
|
||||||
bool32 TestMoveFlagsInMoveset(u8 battler, u32 flags);
|
bool32 TestMoveFlagsInMoveset(u8 battler, u32 flags);
|
||||||
bool32 IsAromaVeilProtectedMove(u16 move);
|
bool32 IsAromaVeilProtectedMove(u16 move);
|
||||||
bool32 IsNonVolatileStatusMoveEffect(u16 moveEffect);
|
bool32 IsNonVolatileStatusMoveEffect(u16 moveEffect);
|
||||||
@ -70,13 +72,13 @@ bool32 MoveRequiresRecharging(u16 move);
|
|||||||
bool32 IsInstructBannedMove(u16 move);
|
bool32 IsInstructBannedMove(u16 move);
|
||||||
|
|
||||||
// status checks
|
// status checks
|
||||||
bool32 AI_ShouldPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove);
|
bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove);
|
||||||
bool32 AI_ShouldPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove);
|
bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove);
|
||||||
bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove);
|
bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove);
|
||||||
bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof);
|
|
||||||
bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove);
|
bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove);
|
||||||
bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove);
|
bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove);
|
||||||
bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGender, u8 defGender);
|
bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGender, u8 defGender);
|
||||||
|
bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof);
|
||||||
|
|
||||||
// partner logic
|
// partner logic
|
||||||
u16 GetAllyChosenMove(void);
|
u16 GetAllyChosenMove(void);
|
||||||
@ -91,4 +93,9 @@ bool32 PartnerMoveIs(u8 battlerAtkPartner, u16 partnerMove, u16 moveCheck);
|
|||||||
bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove);
|
bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove);
|
||||||
bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove);
|
bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove);
|
||||||
|
|
||||||
|
// party logic
|
||||||
|
s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon);
|
||||||
|
s32 CountUsablePartyMons(u8 battlerId);
|
||||||
|
bool32 IsPartyFullyHealedExceptBattler(u8 battler);
|
||||||
|
|
||||||
#endif //GUARD_BATTLE_AI_UTIL_H
|
#endif //GUARD_BATTLE_AI_UTIL_H
|
@ -38,7 +38,7 @@
|
|||||||
// AI Flags. Most run specific functions to update score, new flags are used for internal logic in other scripts
|
// 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_CHECK_BAD_MOVE (1 << 0)
|
||||||
#define AI_FLAG_TRY_TO_FAINT (1 << 1)
|
#define AI_FLAG_TRY_TO_FAINT (1 << 1)
|
||||||
#define AI_FLAG_CHECK_VIABILITY (1 << 2)
|
#define AI_FLAG_CHECK_GOOD_MOVE (1 << 2) // was AI_SCRIPT_CHECK_VIABILITY
|
||||||
#define AI_FLAG_SETUP_FIRST_TURN (1 << 3)
|
#define AI_FLAG_SETUP_FIRST_TURN (1 << 3)
|
||||||
#define AI_FLAG_RISKY (1 << 4)
|
#define AI_FLAG_RISKY (1 << 4)
|
||||||
#define AI_FLAG_PREFER_STRONGEST_MOVE (1 << 5)
|
#define AI_FLAG_PREFER_STRONGEST_MOVE (1 << 5)
|
||||||
@ -49,6 +49,7 @@
|
|||||||
#define AI_FLAG_NEGATE_AWARE (1 << 9) // AI is aware of negating effects like wonder room, mold breaker, etc (eg. smart trainers). TODO unfinished
|
#define AI_FLAG_NEGATE_AWARE (1 << 9) // AI is aware of negating effects like wonder room, mold breaker, etc (eg. smart trainers). TODO unfinished
|
||||||
#define AI_FLAG_HELP_PARTNER (1 << 10) // AI can try to help partner. If not set, will tend not to target partner
|
#define AI_FLAG_HELP_PARTNER (1 << 10) // AI can try to help partner. If not set, will tend not to target partner
|
||||||
#define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc
|
#define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc
|
||||||
|
#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
|
||||||
|
|
||||||
// 'other' ai logic flags
|
// 'other' ai logic flags
|
||||||
#define AI_FLAG_ROAMING (1 << 29)
|
#define AI_FLAG_ROAMING (1 << 29)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "battle.h"
|
#include "battle.h"
|
||||||
#include "battle_ai_script_commands.h"
|
#include "battle_ai_script_commands.h"
|
||||||
|
#include "battle_ai_util.h"
|
||||||
#include "battle_anim.h"
|
#include "battle_anim.h"
|
||||||
#include "battle_controllers.h"
|
#include "battle_controllers.h"
|
||||||
#include "battle_setup.h"
|
#include "battle_setup.h"
|
||||||
|
@ -266,6 +266,63 @@ bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// move checks
|
||||||
|
static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef)
|
||||||
|
{
|
||||||
|
bool32 isCrit;
|
||||||
|
|
||||||
|
switch (CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE))
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
isCrit = FALSE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (gBattleMoves[move].flags & FLAG_HIGH_CRIT && (Random() % 5 == 0))
|
||||||
|
isCrit = TRUE;
|
||||||
|
else
|
||||||
|
isCrit = FALSE;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (gBattleMoves[move].flags & FLAG_HIGH_CRIT && (Random() % 2 == 0))
|
||||||
|
isCrit = TRUE;
|
||||||
|
else if (!(gBattleMoves[move].flags & FLAG_HIGH_CRIT) && (Random() % 4) == 0)
|
||||||
|
isCrit = TRUE;
|
||||||
|
else
|
||||||
|
isCrit = FALSE;
|
||||||
|
break;
|
||||||
|
case -2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
isCrit = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isCrit;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
|
||||||
|
{
|
||||||
|
s32 dmg, moveType;
|
||||||
|
|
||||||
|
SaveBattlerData(battlerAtk);
|
||||||
|
SaveBattlerData(battlerDef);
|
||||||
|
|
||||||
|
SetBattlerData(battlerAtk);
|
||||||
|
SetBattlerData(battlerDef);
|
||||||
|
|
||||||
|
gBattleStruct->dynamicMoveType = 0;
|
||||||
|
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||||
|
GET_MOVE_TYPE(move, moveType);
|
||||||
|
dmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, AI_GetIfCrit(move, battlerAtk, battlerDef), FALSE, FALSE);
|
||||||
|
|
||||||
|
RestoreBattlerData(battlerAtk);
|
||||||
|
RestoreBattlerData(battlerDef);
|
||||||
|
|
||||||
|
return dmg;
|
||||||
|
}
|
||||||
|
|
||||||
// Checks if one of the moves has side effects or perks
|
// Checks if one of the moves has side effects or perks
|
||||||
static u32 WhichMoveBetter(u32 move1, u32 move2)
|
static u32 WhichMoveBetter(u32 move1, u32 move2)
|
||||||
{
|
{
|
||||||
@ -324,7 +381,7 @@ static u32 WhichMoveBetter(u32 move1, u32 move2)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 GetMovePowerResult(u16 move)
|
u8 GetMoveDamageResult(u16 move)
|
||||||
{
|
{
|
||||||
s32 i, checkedMove, bestId, currId, hp;
|
s32 i, checkedMove, bestId, currId, hp;
|
||||||
s32 moveDmgs[MAX_MON_MOVES];
|
s32 moveDmgs[MAX_MON_MOVES];
|
||||||
@ -458,8 +515,8 @@ u8 AI_GetMoveEffectiveness(u16 move)
|
|||||||
return damageVar;
|
return damageVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0: is user(ai) faster
|
// AI_CHECK_FASTER: is user(ai) faster
|
||||||
// 1: is target faster
|
// AI_CHECK_SLOWER: is target faster
|
||||||
bool32 IsBattlerFaster(u8 battler)
|
bool32 IsBattlerFaster(u8 battler)
|
||||||
{
|
{
|
||||||
u32 fasterAI = 0, fasterPlayer = 0, i;
|
u32 fasterAI = 0, fasterPlayer = 0, i;
|
||||||
@ -525,6 +582,26 @@ bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if target has means to faint ai mon after modding hp/dmg
|
||||||
|
bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP);
|
||||||
|
u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef];
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||||
|
{
|
||||||
|
u32 dmg = AI_CalcDamage(moves[i], battlerDef, battlerAtk) + dmgMod;
|
||||||
|
u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod;
|
||||||
|
if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i]) && dmg >= hpCheck)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
// does NOT include ability suppression checks
|
// does NOT include ability suppression checks
|
||||||
s32 AI_GetAbility(u32 battlerId)
|
s32 AI_GetAbility(u32 battlerId)
|
||||||
{
|
{
|
||||||
@ -954,42 +1031,6 @@ bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 CountUsablePartyMons(u8 battlerId)
|
|
||||||
{
|
|
||||||
s32 battlerOnField1, battlerOnField2, i, ret;
|
|
||||||
struct Pokemon *party;
|
|
||||||
|
|
||||||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
|
||||||
party = gPlayerParty;
|
|
||||||
else
|
|
||||||
party = gEnemyParty;
|
|
||||||
|
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
||||||
{
|
|
||||||
battlerOnField1 = gBattlerPartyIndexes[battlerId];
|
|
||||||
battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(GetBattlerPosition(battlerId) ^ BIT_FLANK)];
|
|
||||||
}
|
|
||||||
else // In singles there's only one battlerId by side.
|
|
||||||
{
|
|
||||||
battlerOnField1 = gBattlerPartyIndexes[battlerId];
|
|
||||||
battlerOnField2 = gBattlerPartyIndexes[battlerId];
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
for (i = 0; i < PARTY_SIZE; i++)
|
|
||||||
{
|
|
||||||
if (i != battlerOnField1 && i != battlerOnField2
|
|
||||||
&& GetMonData(&party[i], MON_DATA_HP) != 0
|
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
|
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
|
|
||||||
{
|
|
||||||
ret++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 *GetMovesArray(u32 battler)
|
u16 *GetMovesArray(u32 battler)
|
||||||
{
|
{
|
||||||
if (IsBattlerAIControlled(battler) || IsBattlerAIControlled(BATTLE_PARTNER(battler)))
|
if (IsBattlerAIControlled(battler) || IsBattlerAIControlled(BATTLE_PARTNER(battler)))
|
||||||
@ -1026,6 +1067,20 @@ bool32 HasMoveWithType(u32 battler, u8 type)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool32 HasMoveEffect(u32 battlerId, u16 moveEffect)
|
||||||
|
{
|
||||||
|
s32 i;
|
||||||
|
u16 *moves = GetMovesArray(battlerId);
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||||
|
{
|
||||||
|
if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && gBattleMoves[moves[i]].effect == moveEffect)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
bool32 IsInstructBannedMove(u16 move)
|
bool32 IsInstructBannedMove(u16 move)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
@ -1251,7 +1306,7 @@ bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// status checks
|
// status checks
|
||||||
bool32 AI_ShouldPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove)
|
bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove)
|
||||||
{
|
{
|
||||||
if (defAbility == ABILITY_INSOMNIA
|
if (defAbility == ABILITY_INSOMNIA
|
||||||
|| defAbility == ABILITY_VITAL_SPIRIT
|
|| defAbility == ABILITY_VITAL_SPIRIT
|
||||||
@ -1264,7 +1319,7 @@ bool32 AI_ShouldPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 mov
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool32 AI_ShouldPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove)
|
bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove)
|
||||||
{
|
{
|
||||||
if (defAbility == ABILITY_IMMUNITY
|
if (defAbility == ABILITY_IMMUNITY
|
||||||
|| defAbility == ABILITY_PASTEL_VEIL
|
|| defAbility == ABILITY_PASTEL_VEIL
|
||||||
@ -1358,28 +1413,6 @@ bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool32 IsPartyFullyHealedExceptBattler(u8 battlerId)
|
|
||||||
{
|
|
||||||
struct Pokemon *party;
|
|
||||||
u32 i;
|
|
||||||
|
|
||||||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
|
||||||
party = gPlayerParty;
|
|
||||||
else
|
|
||||||
party = gEnemyParty;
|
|
||||||
|
|
||||||
for (i = 0; i < PARTY_SIZE; i++)
|
|
||||||
{
|
|
||||||
if (i != gBattlerPartyIndexes[battlerId]
|
|
||||||
&& GetMonData(&party[i], MON_DATA_HP) != 0
|
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
|
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG
|
|
||||||
&& GetMonData(&party[i], MON_DATA_HP) < GetMonData(&party[i], MON_DATA_MAX_HP))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 GetBattlerSideSpeedAverage(u8 battler)
|
u16 GetBattlerSideSpeedAverage(u8 battler)
|
||||||
{
|
{
|
||||||
u16 speed1 = 0;
|
u16 speed1 = 0;
|
||||||
@ -1415,6 +1448,30 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage)
|
||||||
|
{
|
||||||
|
if (move == 0xFFFF || GetWhoStrikesFirst(sBattler_AI, gBattlerTarget, TRUE) == 0)
|
||||||
|
{
|
||||||
|
// using item or user goes first
|
||||||
|
u8 healPercent = (gBattleMoves[move].argument == 0) ? 50 : gBattleMoves[move].argument;
|
||||||
|
s32 healDmg = (healPercent * damage) / 100;
|
||||||
|
|
||||||
|
if (CanTargetFaintAi(battlerDef, battlerAtk)
|
||||||
|
&& !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healDmg, 0))
|
||||||
|
return TRUE; // target can faint attacker unless they heal
|
||||||
|
else if (!CanTargetFaintAi(battlerDef, battlerAtk) && GetHealthPercentage(battlerAtk) < 60 && (Random() % 3))
|
||||||
|
return TRUE; // target can't faint attacker at all, attacker health is about half, 2/3rds rate of encouraging healing
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// opponent goes first
|
||||||
|
if (!CanTargetFaintAi(battlerDef, battlerAtk))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
// Partner Logic
|
// Partner Logic
|
||||||
bool32 IsValidDoubleBattle(u8 battlerAtk)
|
bool32 IsValidDoubleBattle(u8 battlerAtk)
|
||||||
{
|
{
|
||||||
@ -1556,3 +1613,82 @@ bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// party logic
|
||||||
|
s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon)
|
||||||
|
{
|
||||||
|
s32 dmg;
|
||||||
|
u32 i;
|
||||||
|
struct BattlePokemon *battleMons = Alloc(sizeof(struct BattlePokemon) * MAX_BATTLERS_COUNT);
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||||
|
battleMons[i] = gBattleMons[i];
|
||||||
|
|
||||||
|
PokemonToBattleMon(mon, &gBattleMons[battlerAtk]);
|
||||||
|
dmg = AI_CalcDamage(move, battlerAtk, battlerDef);
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||||
|
gBattleMons[i] = battleMons[i];
|
||||||
|
|
||||||
|
Free(battleMons);
|
||||||
|
|
||||||
|
return dmg;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 CountUsablePartyMons(u8 battlerId)
|
||||||
|
{
|
||||||
|
s32 battlerOnField1, battlerOnField2, i, ret;
|
||||||
|
struct Pokemon *party;
|
||||||
|
|
||||||
|
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||||
|
party = gPlayerParty;
|
||||||
|
else
|
||||||
|
party = gEnemyParty;
|
||||||
|
|
||||||
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||||
|
{
|
||||||
|
battlerOnField1 = gBattlerPartyIndexes[battlerId];
|
||||||
|
battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(GetBattlerPosition(battlerId) ^ BIT_FLANK)];
|
||||||
|
}
|
||||||
|
else // In singles there's only one battlerId by side.
|
||||||
|
{
|
||||||
|
battlerOnField1 = gBattlerPartyIndexes[battlerId];
|
||||||
|
battlerOnField2 = gBattlerPartyIndexes[battlerId];
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
for (i = 0; i < PARTY_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (i != battlerOnField1 && i != battlerOnField2
|
||||||
|
&& GetMonData(&party[i], MON_DATA_HP) != 0
|
||||||
|
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
|
||||||
|
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
|
||||||
|
{
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool32 IsPartyFullyHealedExceptBattler(u8 battlerId)
|
||||||
|
{
|
||||||
|
struct Pokemon *party;
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||||
|
party = gPlayerParty;
|
||||||
|
else
|
||||||
|
party = gEnemyParty;
|
||||||
|
|
||||||
|
for (i = 0; i < PARTY_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (i != gBattlerPartyIndexes[battlerId]
|
||||||
|
&& GetMonData(&party[i], MON_DATA_HP) != 0
|
||||||
|
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
|
||||||
|
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG
|
||||||
|
&& GetMonData(&party[i], MON_DATA_HP) < GetMonData(&party[i], MON_DATA_MAX_HP))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -850,13 +850,13 @@ u32 GetAiScriptsInBattleFactory(void)
|
|||||||
int challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7;
|
int challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7;
|
||||||
|
|
||||||
if (gTrainerBattleOpponent_A == TRAINER_FRONTIER_BRAIN)
|
if (gTrainerBattleOpponent_A == TRAINER_FRONTIER_BRAIN)
|
||||||
return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY;
|
return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE;
|
||||||
else if (challengeNum < 2)
|
else if (challengeNum < 2)
|
||||||
return 0;
|
return 0;
|
||||||
else if (challengeNum < 4)
|
else if (challengeNum < 4)
|
||||||
return AI_FLAG_CHECK_BAD_MOVE;
|
return AI_FLAG_CHECK_BAD_MOVE;
|
||||||
else
|
else
|
||||||
return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY;
|
return AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "battle.h"
|
#include "battle.h"
|
||||||
#include "battle_anim.h"
|
#include "battle_anim.h"
|
||||||
#include "battle_ai_script_commands.h"
|
#include "battle_ai_script_commands.h"
|
||||||
|
#include "battle_ai_util.h"
|
||||||
#include "battle_arena.h"
|
#include "battle_arena.h"
|
||||||
#include "battle_controllers.h"
|
#include "battle_controllers.h"
|
||||||
#include "battle_interface.h"
|
#include "battle_interface.h"
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "battle_message.h"
|
#include "battle_message.h"
|
||||||
#include "battle_anim.h"
|
#include "battle_anim.h"
|
||||||
#include "battle_ai_script_commands.h"
|
#include "battle_ai_script_commands.h"
|
||||||
|
#include "battle_ai_util.h"
|
||||||
#include "battle_scripts.h"
|
#include "battle_scripts.h"
|
||||||
#include "constants/moves.h"
|
#include "constants/moves.h"
|
||||||
#include "constants/abilities.h"
|
#include "constants/abilities.h"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "battle_message.h"
|
#include "battle_message.h"
|
||||||
#include "battle_ai_script_commands.h"
|
#include "battle_ai_script_commands.h"
|
||||||
|
#include "battle_ai_util.h"
|
||||||
#include "event_data.h"
|
#include "event_data.h"
|
||||||
#include "link.h"
|
#include "link.h"
|
||||||
#include "malloc.h"
|
#include "malloc.h"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -897,7 +897,7 @@ void FillHillTrainersParties(void)
|
|||||||
// hill trainers.
|
// hill trainers.
|
||||||
u32 GetTrainerHillAIFlags(void)
|
u32 GetTrainerHillAIFlags(void)
|
||||||
{
|
{
|
||||||
return (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY);
|
return (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_GOOD_MOVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 GetTrainerEncounterMusicIdInTrainerHill(u16 trainerId)
|
u8 GetTrainerEncounterMusicIdInTrainerHill(u16 trainerId)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user