Move out ai structs out of BattleResources (#6741)
This commit is contained in:
commit
d09a06561f
@ -282,16 +282,17 @@ struct AiPartyMon
|
||||
u16 item;
|
||||
u16 heldEffect;
|
||||
u16 ability;
|
||||
u16 gender;
|
||||
u16 level;
|
||||
u16 moves[MAX_MON_MOVES];
|
||||
u32 status;
|
||||
bool8 isFainted;
|
||||
bool8 wasSentInBattle;
|
||||
u8 switchInCount; // Counts how many times this Pokemon has been sent out or switched into in a battle.
|
||||
u8 gender:2;
|
||||
u8 isFainted:1;
|
||||
u8 wasSentInBattle:1;
|
||||
u8 padding:4;
|
||||
};
|
||||
|
||||
struct AIPartyData // Opposing battlers - party mons.
|
||||
struct AiPartyData // Opposing battlers - party mons.
|
||||
{
|
||||
struct AiPartyMon mons[NUM_BATTLE_SIDES][PARTY_SIZE]; // 2 parties(player, opponent). Used to save information on opposing party.
|
||||
u8 count[NUM_BATTLE_SIDES];
|
||||
@ -341,7 +342,7 @@ struct AiLogicData
|
||||
u16 predictedMove[MAX_BATTLERS_COUNT];
|
||||
};
|
||||
|
||||
struct AI_ThinkingStruct
|
||||
struct AiThinkingStruct
|
||||
{
|
||||
u8 aiState;
|
||||
u8 movesetIndex;
|
||||
@ -392,20 +393,11 @@ struct BattleResources
|
||||
struct BattleScriptsStack* battleScriptsStack;
|
||||
struct BattleCallbacksStack* battleCallbackStack;
|
||||
struct StatsArray* beforeLvlUp;
|
||||
struct AI_ThinkingStruct *ai;
|
||||
struct AiLogicData *aiData;
|
||||
struct AIPartyData *aiParty;
|
||||
struct BattleHistory *battleHistory;
|
||||
u8 bufferA[MAX_BATTLERS_COUNT][0x200];
|
||||
u8 bufferB[MAX_BATTLERS_COUNT][0x200];
|
||||
u8 transferBuffer[0x100];
|
||||
};
|
||||
|
||||
#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai))
|
||||
#define AI_DATA ((struct AiLogicData *)(gBattleResources->aiData))
|
||||
#define AI_PARTY ((struct AIPartyData *)(gBattleResources->aiParty))
|
||||
#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory))
|
||||
|
||||
struct BattleResults
|
||||
{
|
||||
u8 playerFaintCounter; // 0x0
|
||||
@ -1107,6 +1099,10 @@ extern struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT];
|
||||
extern struct BattleScripting gBattleScripting;
|
||||
extern struct BattleStruct *gBattleStruct;
|
||||
extern struct AiBattleData *gAiBattleData;
|
||||
extern struct AiThinkingStruct *gAiThinkingStruct;
|
||||
extern struct AiLogicData *gAiLogicData;
|
||||
extern struct AiPartyData *gAiPartyData;
|
||||
extern struct BattleHistory *gBattleHistory;
|
||||
extern u8 *gLinkBattleSendBuffer;
|
||||
extern u8 *gLinkBattleRecvBuffer;
|
||||
extern struct BattleResources *gBattleResources;
|
||||
|
||||
@ -60,7 +60,7 @@ enum AIScore
|
||||
{ \
|
||||
TestRunner_Battle_AISetScore(__FILE__, __LINE__, battler, movesetIndex, val); \
|
||||
} \
|
||||
AI_THINKING_STRUCT->score[movesetIndex] = val; \
|
||||
gAiThinkingStruct->score[movesetIndex] = val; \
|
||||
} while (0) \
|
||||
|
||||
#define ADJUST_SCORE(val) \
|
||||
@ -68,7 +68,7 @@ enum AIScore
|
||||
{ \
|
||||
if (TESTING) \
|
||||
{ \
|
||||
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, AI_THINKING_STRUCT->movesetIndex, val); \
|
||||
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, gAiThinkingStruct->movesetIndex, val); \
|
||||
} \
|
||||
score += val; \
|
||||
} while (0) \
|
||||
@ -78,7 +78,7 @@ enum AIScore
|
||||
{ \
|
||||
if (TESTING) \
|
||||
{ \
|
||||
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, AI_THINKING_STRUCT->movesetIndex, val); \
|
||||
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, gAiThinkingStruct->movesetIndex, val); \
|
||||
} \
|
||||
score += val; \
|
||||
return score; \
|
||||
@ -89,7 +89,7 @@ enum AIScore
|
||||
{ \
|
||||
if (TESTING) \
|
||||
{ \
|
||||
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, AI_THINKING_STRUCT->movesetIndex, val); \
|
||||
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, gAiThinkingStruct->movesetIndex, val); \
|
||||
} \
|
||||
(*score) += val; \
|
||||
} while (0) \
|
||||
|
||||
@ -34,8 +34,8 @@
|
||||
|
||||
static u32 ChooseMoveOrAction_Singles(u32 battler);
|
||||
static u32 ChooseMoveOrAction_Doubles(u32 battler);
|
||||
static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battlerAtk, u32 battlerDef);
|
||||
static inline void BattleAI_DoAIProcessing_PredictedSwitchin(struct AI_ThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef);
|
||||
static inline void BattleAI_DoAIProcessing(struct AiThinkingStruct *aiThink, u32 battlerAtk, u32 battlerDef);
|
||||
static inline void BattleAI_DoAIProcessing_PredictedSwitchin(struct AiThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef);
|
||||
static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect);
|
||||
|
||||
// ewram
|
||||
@ -132,7 +132,7 @@ static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) =
|
||||
void BattleAI_SetupItems(void)
|
||||
{
|
||||
s32 i;
|
||||
u8 *data = (u8 *)BATTLE_HISTORY;
|
||||
u8 *data = (u8 *)gBattleHistory;
|
||||
const u16 *items = GetTrainerItemsFromId(TRAINER_BATTLE_PARAM.opponentA);
|
||||
|
||||
for (i = 0; i < sizeof(struct BattleHistory); i++)
|
||||
@ -150,8 +150,8 @@ void BattleAI_SetupItems(void)
|
||||
{
|
||||
if (items[i] != ITEM_NONE)
|
||||
{
|
||||
BATTLE_HISTORY->trainerItems[BATTLE_HISTORY->itemsNo] = items[i];
|
||||
BATTLE_HISTORY->itemsNo++;
|
||||
gBattleHistory->trainerItems[gBattleHistory->itemsNo] = items[i];
|
||||
gBattleHistory->itemsNo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -229,43 +229,43 @@ static u64 GetAiFlags(u16 trainerId)
|
||||
void BattleAI_SetupFlags(void)
|
||||
{
|
||||
if (IsAiVsAiBattle())
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId);
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId);
|
||||
else
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI
|
||||
|
||||
if (DEBUG_OVERWORLD_MENU && gIsDebugBattle)
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags;
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags;
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags;
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsWildMonSmart() && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))
|
||||
{
|
||||
// smart wild AI
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF);
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF);
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF);
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA);
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA);
|
||||
if (TRAINER_BATTLE_PARAM.opponentB != 0)
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB);
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB);
|
||||
else
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT];
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT];
|
||||
}
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE));
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE));
|
||||
}
|
||||
else if (IsDoubleBattle() && IsAiVsAiBattle())
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT];
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT];
|
||||
}
|
||||
else
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = 0; // player
|
||||
gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = 0; // player
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,11 +277,11 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
|
||||
u32 moveIndex;
|
||||
|
||||
// Clear AI data but preserve the flags.
|
||||
memcpy(&flags[0], &AI_THINKING_STRUCT->aiFlags[0], sizeof(u64) * MAX_BATTLERS_COUNT);
|
||||
memset(AI_THINKING_STRUCT, 0, sizeof(struct AI_ThinkingStruct));
|
||||
memcpy(&AI_THINKING_STRUCT->aiFlags[0], &flags[0], sizeof(u64) * MAX_BATTLERS_COUNT);
|
||||
memcpy(&flags[0], &gAiThinkingStruct->aiFlags[0], sizeof(u64) * MAX_BATTLERS_COUNT);
|
||||
memset(gAiThinkingStruct, 0, sizeof(struct AiThinkingStruct));
|
||||
memcpy(&gAiThinkingStruct->aiFlags[0], &flags[0], sizeof(u64) * MAX_BATTLERS_COUNT);
|
||||
|
||||
moveLimitations = AI_DATA->moveLimitations[battler];
|
||||
moveLimitations = gAiLogicData->moveLimitations[battler];
|
||||
|
||||
// Conditional score reset, unlike Ruby.
|
||||
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
|
||||
@ -300,10 +300,10 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
|
||||
gAiBattleData->chosenTarget[battler] = gBattlerTarget;
|
||||
|
||||
// Initialize move prediction scores
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVE)
|
||||
if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_MOVE)
|
||||
{
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
moveLimitationsTarget = AI_DATA->moveLimitations[opposingBattler];
|
||||
moveLimitationsTarget = gAiLogicData->moveLimitations[opposingBattler];
|
||||
|
||||
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
|
||||
{
|
||||
@ -321,13 +321,13 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
|
||||
|
||||
bool32 BattlerChoseNonMoveAction(void)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE)
|
||||
if (gAiThinkingStruct->aiAction & AI_ACTION_FLEE)
|
||||
{
|
||||
gAiBattleData->actionFlee = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH)
|
||||
if (gAiThinkingStruct->aiAction & AI_ACTION_WATCH)
|
||||
{
|
||||
gAiBattleData->choiceWatch = TRUE;
|
||||
return TRUE;
|
||||
@ -339,32 +339,32 @@ bool32 BattlerChoseNonMoveAction(void)
|
||||
void SetupAIPredictionData(u32 battler, enum SwitchType switchType)
|
||||
{
|
||||
s32 opposingBattler = GetOppositeBattler(battler);
|
||||
AI_DATA->aiPredictionInProgress = TRUE;
|
||||
AI_DATA->battlerDoingPrediction = battler;
|
||||
|
||||
gAiLogicData->aiPredictionInProgress = TRUE;
|
||||
gAiLogicData->battlerDoingPrediction = battler;
|
||||
|
||||
// Switch prediction
|
||||
if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_SWITCH))
|
||||
if ((gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_SWITCH))
|
||||
{
|
||||
AI_DATA->mostSuitableMonId[opposingBattler] = GetMostSuitableMonToSwitchInto(opposingBattler, switchType);
|
||||
gAiLogicData->mostSuitableMonId[opposingBattler] = GetMostSuitableMonToSwitchInto(opposingBattler, switchType);
|
||||
if (ShouldSwitch(opposingBattler))
|
||||
AI_DATA->shouldSwitch |= (1u << opposingBattler);
|
||||
gAiLogicData->shouldSwitch |= (1u << opposingBattler);
|
||||
gBattleStruct->prevTurnSpecies[opposingBattler] = gBattleMons[opposingBattler].species;
|
||||
|
||||
// Determine whether AI will use predictions this turn
|
||||
AI_DATA->predictingSwitch = RandomPercentage(RNG_AI_PREDICT_SWITCH, PREDICT_SWITCH_CHANCE);
|
||||
gAiLogicData->predictingSwitch = RandomPercentage(RNG_AI_PREDICT_SWITCH, PREDICT_SWITCH_CHANCE);
|
||||
}
|
||||
|
||||
// Move prediction
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVE)
|
||||
if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_MOVE)
|
||||
{
|
||||
AI_DATA->predictedMove[opposingBattler] = gBattleMons[opposingBattler].moves[BattleAI_ChooseMoveIndex(opposingBattler)];
|
||||
DebugPrintf("Predicted move: %d", AI_DATA->predictedMove[opposingBattler]);
|
||||
gAiLogicData->predictedMove[opposingBattler] = gBattleMons[opposingBattler].moves[BattleAI_ChooseMoveIndex(opposingBattler)];
|
||||
DebugPrintf("Predicted move: %d", gAiLogicData->predictedMove[opposingBattler]);
|
||||
ModifySwitchAfterMoveScoring(opposingBattler);
|
||||
|
||||
// Determine whether AI will use predictions this turn
|
||||
AI_DATA->predictingMove = RandomPercentage(RNG_AI_PREDICT_MOVE, PREDICT_MOVE_CHANCE);
|
||||
gAiLogicData->predictingMove = RandomPercentage(RNG_AI_PREDICT_MOVE, PREDICT_MOVE_CHANCE);
|
||||
}
|
||||
AI_DATA->aiPredictionInProgress = FALSE;
|
||||
gAiLogicData->aiPredictionInProgress = FALSE;
|
||||
}
|
||||
|
||||
void ComputeBattlerDecisions(u32 battler)
|
||||
@ -378,25 +378,25 @@ void ComputeBattlerDecisions(u32 battler)
|
||||
return;
|
||||
|
||||
// Risky AI switches aggressively even mid battle
|
||||
enum SwitchType switchType = (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE;
|
||||
enum SwitchType switchType = (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE;
|
||||
|
||||
AI_DATA->aiCalcInProgress = TRUE;
|
||||
gAiLogicData->aiCalcInProgress = TRUE;
|
||||
|
||||
// Setup battler and prediction data
|
||||
BattleAI_SetupAIData(0xF, battler);
|
||||
SetupAIPredictionData(battler, switchType);
|
||||
|
||||
// AI's own switching data
|
||||
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, switchType);
|
||||
gAiLogicData->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, switchType);
|
||||
if (ShouldSwitch(battler))
|
||||
AI_DATA->shouldSwitch |= (1u << battler);
|
||||
gAiLogicData->shouldSwitch |= (1u << battler);
|
||||
gBattleStruct->prevTurnSpecies[battler] = gBattleMons[battler].species;
|
||||
|
||||
// AI's move scoring
|
||||
gAiBattleData->chosenMoveIndex[battler] = BattleAI_ChooseMoveIndex(battler); // Calculate score and chose move index
|
||||
ModifySwitchAfterMoveScoring(battler);
|
||||
|
||||
AI_DATA->aiCalcInProgress = FALSE;
|
||||
gAiLogicData->aiCalcInProgress = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,7 +422,7 @@ u32 BattleAI_ChooseMoveIndex(u32 battler)
|
||||
static void CopyBattlerDataToAIParty(u32 bPosition, u32 side)
|
||||
{
|
||||
u32 battler = GetBattlerAtPosition(bPosition);
|
||||
struct AiPartyMon *aiMon = &AI_PARTY->mons[side][gBattlerPartyIndexes[battler]];
|
||||
struct AiPartyMon *aiMon = &gAiPartyData->mons[side][gBattlerPartyIndexes[battler]];
|
||||
struct BattlePokemon *bMon = &gBattleMons[battler];
|
||||
|
||||
aiMon->species = bMon->species;
|
||||
@ -437,11 +437,11 @@ static void CopyBattlerDataToAIParty(u32 bPosition, u32 side)
|
||||
void Ai_InitPartyStruct(void)
|
||||
{
|
||||
u32 i;
|
||||
bool32 isOmniscient = (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT) || (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT);
|
||||
bool32 isOmniscient = (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT) || (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT);
|
||||
struct Pokemon *mon;
|
||||
|
||||
AI_PARTY->count[B_SIDE_PLAYER] = CalculatePlayerPartyCount();
|
||||
AI_PARTY->count[B_SIDE_OPPONENT] = CalculateEnemyPartyCount();
|
||||
gAiPartyData->count[B_SIDE_PLAYER] = CalculatePlayerPartyCount();
|
||||
gAiPartyData->count[B_SIDE_OPPONENT] = CalculateEnemyPartyCount();
|
||||
|
||||
// Save first 2 or 4(in doubles) mons
|
||||
CopyBattlerDataToAIParty(B_POSITION_PLAYER_LEFT, B_SIDE_PLAYER);
|
||||
@ -456,20 +456,20 @@ void Ai_InitPartyStruct(void)
|
||||
}
|
||||
|
||||
// Find fainted mons
|
||||
for (i = 0; i < AI_PARTY->count[B_SIDE_PLAYER]; i++)
|
||||
for (i = 0; i < gAiPartyData->count[B_SIDE_PLAYER]; i++)
|
||||
{
|
||||
if (GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0)
|
||||
AI_PARTY->mons[B_SIDE_PLAYER][i].isFainted = TRUE;
|
||||
gAiPartyData->mons[B_SIDE_PLAYER][i].isFainted = TRUE;
|
||||
|
||||
if (isOmniscient)
|
||||
{
|
||||
u32 j;
|
||||
mon = &gPlayerParty[i];
|
||||
AI_PARTY->mons[B_SIDE_PLAYER][i].item = GetMonData(mon, MON_DATA_HELD_ITEM);
|
||||
AI_PARTY->mons[B_SIDE_PLAYER][i].heldEffect = ItemId_GetHoldEffect(AI_PARTY->mons[B_SIDE_PLAYER][i].item);
|
||||
AI_PARTY->mons[B_SIDE_PLAYER][i].ability = GetMonAbility(mon);
|
||||
gAiPartyData->mons[B_SIDE_PLAYER][i].item = GetMonData(mon, MON_DATA_HELD_ITEM);
|
||||
gAiPartyData->mons[B_SIDE_PLAYER][i].heldEffect = ItemId_GetHoldEffect(gAiPartyData->mons[B_SIDE_PLAYER][i].item);
|
||||
gAiPartyData->mons[B_SIDE_PLAYER][i].ability = GetMonAbility(mon);
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
AI_PARTY->mons[B_SIDE_PLAYER][i].moves[j] = GetMonData(mon, MON_DATA_MOVE1 + j);
|
||||
gAiPartyData->mons[B_SIDE_PLAYER][i].moves[j] = GetMonData(mon, MON_DATA_MOVE1 + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -478,19 +478,19 @@ void Ai_UpdateSwitchInData(u32 battler)
|
||||
{
|
||||
u32 i;
|
||||
u32 side = GetBattlerSide(battler);
|
||||
struct AiPartyMon *aiMon = &AI_PARTY->mons[side][gBattlerPartyIndexes[battler]];
|
||||
struct AiPartyMon *aiMon = &gAiPartyData->mons[side][gBattlerPartyIndexes[battler]];
|
||||
|
||||
// See if the switched-in mon has been already in battle
|
||||
if (aiMon->wasSentInBattle)
|
||||
{
|
||||
if (aiMon->ability)
|
||||
BATTLE_HISTORY->abilities[battler] = aiMon->ability;
|
||||
gBattleHistory->abilities[battler] = aiMon->ability;
|
||||
if (aiMon->heldEffect)
|
||||
BATTLE_HISTORY->itemEffects[battler] = aiMon->heldEffect;
|
||||
gBattleHistory->itemEffects[battler] = aiMon->heldEffect;
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (aiMon->moves[i])
|
||||
BATTLE_HISTORY->usedMoves[battler][i] = aiMon->moves[i];
|
||||
gBattleHistory->usedMoves[battler][i] = aiMon->moves[i];
|
||||
}
|
||||
aiMon->switchInCount++;
|
||||
aiMon->status = gBattleMons[battler].status1; // Copy status, because it could've been changed in battle.
|
||||
@ -506,7 +506,7 @@ void Ai_UpdateSwitchInData(u32 battler)
|
||||
|
||||
void Ai_UpdateFaintData(u32 battler)
|
||||
{
|
||||
struct AiPartyMon *aiMon = &AI_PARTY->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]];
|
||||
struct AiPartyMon *aiMon = &gAiPartyData->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]];
|
||||
ClearBattlerMoveHistory(battler);
|
||||
ClearBattlerAbilityHistory(battler);
|
||||
ClearBattlerItemEffectHistory(battler);
|
||||
@ -601,7 +601,7 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData)
|
||||
// get/assume all battler data and simulate AI damage
|
||||
battlersCount = gBattlersCount;
|
||||
|
||||
AI_DATA->aiCalcInProgress = TRUE;
|
||||
gAiLogicData->aiCalcInProgress = TRUE;
|
||||
if (DEBUG_AI_DELAY_TIMER)
|
||||
CycleCountStart();
|
||||
for (battlerAtk = 0; battlerAtk < battlersCount; battlerAtk++)
|
||||
@ -622,7 +622,7 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData)
|
||||
if (DEBUG_AI_DELAY_TIMER)
|
||||
// We add to existing to compound multiple calls
|
||||
gBattleStruct->aiDelayCycles += CycleCountEnd();
|
||||
AI_DATA->aiCalcInProgress = FALSE;
|
||||
gAiLogicData->aiCalcInProgress = FALSE;
|
||||
}
|
||||
|
||||
u32 GetPartyMonAbility(struct Pokemon *mon)
|
||||
@ -677,29 +677,29 @@ static u32 ChooseMoveOrAction_Singles(u32 battler)
|
||||
u8 consideredMoveArray[MAX_MON_MOVES];
|
||||
u32 numOfBestMoves;
|
||||
s32 i;
|
||||
u64 flags = AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)];
|
||||
u64 flags = gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)];
|
||||
|
||||
AI_DATA->partnerMove = 0; // no ally
|
||||
gAiLogicData->partnerMove = 0; // no ally
|
||||
while (flags != 0)
|
||||
{
|
||||
if (flags & 1)
|
||||
{
|
||||
if (IsBattlerPredictedToSwitch(gBattlerTarget) && (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_INCOMING_MON))
|
||||
BattleAI_DoAIProcessing_PredictedSwitchin(AI_THINKING_STRUCT, AI_DATA, battler, gBattlerTarget);
|
||||
if (IsBattlerPredictedToSwitch(gBattlerTarget) && (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_INCOMING_MON))
|
||||
BattleAI_DoAIProcessing_PredictedSwitchin(gAiThinkingStruct, gAiLogicData, battler, gBattlerTarget);
|
||||
else
|
||||
BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battler, gBattlerTarget);
|
||||
BattleAI_DoAIProcessing(gAiThinkingStruct, battler, gBattlerTarget);
|
||||
}
|
||||
flags >>= (u64)1;
|
||||
AI_THINKING_STRUCT->aiLogicId++;
|
||||
gAiThinkingStruct->aiLogicId++;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
gAiBattleData->finalScore[battler][gBattlerTarget][i] = AI_THINKING_STRUCT->score[i];
|
||||
gAiBattleData->finalScore[battler][gBattlerTarget][i] = gAiThinkingStruct->score[i];
|
||||
}
|
||||
|
||||
numOfBestMoves = 1;
|
||||
currentMoveArray[0] = AI_THINKING_STRUCT->score[0];
|
||||
currentMoveArray[0] = gAiThinkingStruct->score[0];
|
||||
consideredMoveArray[0] = 0;
|
||||
|
||||
for (i = 1; i < MAX_MON_MOVES; i++)
|
||||
@ -707,15 +707,15 @@ static u32 ChooseMoveOrAction_Singles(u32 battler)
|
||||
if (gBattleMons[battler].moves[i] != MOVE_NONE)
|
||||
{
|
||||
// In ruby, the order of these if statements is reversed.
|
||||
if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i])
|
||||
if (currentMoveArray[0] == gAiThinkingStruct->score[i])
|
||||
{
|
||||
currentMoveArray[numOfBestMoves] = AI_THINKING_STRUCT->score[i];
|
||||
currentMoveArray[numOfBestMoves] = gAiThinkingStruct->score[i];
|
||||
consideredMoveArray[numOfBestMoves++] = i;
|
||||
}
|
||||
if (currentMoveArray[0] < AI_THINKING_STRUCT->score[i])
|
||||
if (currentMoveArray[0] < gAiThinkingStruct->score[i])
|
||||
{
|
||||
numOfBestMoves = 1;
|
||||
currentMoveArray[0] = AI_THINKING_STRUCT->score[i];
|
||||
currentMoveArray[0] = gAiThinkingStruct->score[i];
|
||||
consideredMoveArray[0] = i;
|
||||
}
|
||||
}
|
||||
@ -752,25 +752,25 @@ static u32 ChooseMoveOrAction_Doubles(u32 battler)
|
||||
|
||||
gBattlerTarget = i;
|
||||
|
||||
AI_DATA->partnerMove = GetAllyChosenMove(battler);
|
||||
AI_THINKING_STRUCT->aiLogicId = 0;
|
||||
AI_THINKING_STRUCT->movesetIndex = 0;
|
||||
flags = AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)];
|
||||
gAiLogicData->partnerMove = GetAllyChosenMove(battler);
|
||||
gAiThinkingStruct->aiLogicId = 0;
|
||||
gAiThinkingStruct->movesetIndex = 0;
|
||||
flags = gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)];
|
||||
|
||||
while (flags != 0)
|
||||
{
|
||||
if (flags & 1)
|
||||
{
|
||||
if (IsBattlerPredictedToSwitch(gBattlerTarget) && (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_INCOMING_MON))
|
||||
BattleAI_DoAIProcessing_PredictedSwitchin(AI_THINKING_STRUCT, AI_DATA, battler, gBattlerTarget);
|
||||
if (IsBattlerPredictedToSwitch(gBattlerTarget) && (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_INCOMING_MON))
|
||||
BattleAI_DoAIProcessing_PredictedSwitchin(gAiThinkingStruct, gAiLogicData, battler, gBattlerTarget);
|
||||
else
|
||||
BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battler, gBattlerTarget);
|
||||
BattleAI_DoAIProcessing(gAiThinkingStruct, battler, gBattlerTarget);
|
||||
}
|
||||
flags >>= (u64)1;
|
||||
AI_THINKING_STRUCT->aiLogicId++;
|
||||
gAiThinkingStruct->aiLogicId++;
|
||||
}
|
||||
|
||||
mostViableMovesScores[0] = AI_THINKING_STRUCT->score[0];
|
||||
mostViableMovesScores[0] = gAiThinkingStruct->score[0];
|
||||
mostViableMovesIndices[0] = 0;
|
||||
mostViableMovesNo = 1;
|
||||
for (j = 1; j < MAX_MON_MOVES; j++)
|
||||
@ -780,15 +780,15 @@ static u32 ChooseMoveOrAction_Doubles(u32 battler)
|
||||
if (!CanTargetBattler(battler, i, gBattleMons[battler].moves[j]))
|
||||
continue;
|
||||
|
||||
if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j])
|
||||
if (mostViableMovesScores[0] == gAiThinkingStruct->score[j])
|
||||
{
|
||||
mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j];
|
||||
mostViableMovesScores[mostViableMovesNo] = gAiThinkingStruct->score[j];
|
||||
mostViableMovesIndices[mostViableMovesNo] = j;
|
||||
mostViableMovesNo++;
|
||||
}
|
||||
if (mostViableMovesScores[0] < AI_THINKING_STRUCT->score[j])
|
||||
if (mostViableMovesScores[0] < gAiThinkingStruct->score[j])
|
||||
{
|
||||
mostViableMovesScores[0] = AI_THINKING_STRUCT->score[j];
|
||||
mostViableMovesScores[0] = gAiThinkingStruct->score[j];
|
||||
mostViableMovesIndices[0] = j;
|
||||
mostViableMovesNo = 1;
|
||||
}
|
||||
@ -805,7 +805,7 @@ static u32 ChooseMoveOrAction_Doubles(u32 battler)
|
||||
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
gAiBattleData->finalScore[battler][gBattlerTarget][j] = AI_THINKING_STRUCT->score[j];
|
||||
gAiBattleData->finalScore[battler][gBattlerTarget][j] = gAiThinkingStruct->score[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -845,7 +845,7 @@ static inline bool32 ShouldConsiderMoveForBattler(u32 battlerAi, u32 battlerDef,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battlerAtk, u32 battlerDef)
|
||||
static inline void BattleAI_DoAIProcessing(struct AiThinkingStruct *aiThink, u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
do
|
||||
{
|
||||
@ -880,7 +880,7 @@ static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u3
|
||||
aiThink->movesetIndex = 0;
|
||||
}
|
||||
|
||||
void BattleAI_DoAIProcessing_PredictedSwitchin(struct AI_ThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef)
|
||||
void BattleAI_DoAIProcessing_PredictedSwitchin(struct AiThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
struct BattlePokemon switchoutCandidate = gBattleMons[battlerDef];
|
||||
struct SimulatedDamage simulatedDamageSwitchout[MAX_MON_MOVES];
|
||||
@ -998,12 +998,12 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
s32 moveType;
|
||||
u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move);
|
||||
struct AiLogicData *aiData = AI_DATA;
|
||||
uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
|
||||
struct AiLogicData *aiData = gAiLogicData;
|
||||
uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex];
|
||||
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
|
||||
u32 i;
|
||||
u32 weather;
|
||||
u32 predictedMove = ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? AI_DATA->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
|
||||
u32 predictedMove = ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? gAiLogicData->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
|
||||
u32 abilityAtk = aiData->abilities[battlerAtk];
|
||||
u32 abilityDef = aiData->abilities[battlerDef];
|
||||
s32 atkPriority = GetBattleMovePriority(battlerAtk, abilityAtk, move);
|
||||
@ -1268,7 +1268,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-20);
|
||||
break;
|
||||
case EFFECT_EXPLOSION:
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE))
|
||||
if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE))
|
||||
ADJUST_SCORE(-2);
|
||||
|
||||
if (effectiveness == UQ_4_12(0.0))
|
||||
@ -1618,7 +1618,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-1);
|
||||
if ((predictedMove == MOVE_NONE || GetBattleMoveCategory(predictedMove) == DAMAGE_CATEGORY_STATUS
|
||||
|| DoesSubstituteBlockMove(battlerAtk, BATTLE_PARTNER(battlerDef), predictedMove))
|
||||
&& !(predictedMove == MOVE_NONE && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY))) // Let Risky AI predict blindly based on stats
|
||||
&& !(predictedMove == MOVE_NONE && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY))) // Let Risky AI predict blindly based on stats
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
|
||||
@ -2123,8 +2123,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-8); //No point in healing, but should at least do it if nothing better
|
||||
break;
|
||||
case EFFECT_RECOIL_IF_MISS:
|
||||
if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && AI_DATA->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] < 75
|
||||
&& !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY))
|
||||
if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && gAiLogicData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] < 75
|
||||
&& !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY))
|
||||
ADJUST_SCORE(-6);
|
||||
break;
|
||||
case EFFECT_TRANSFORM:
|
||||
@ -2239,7 +2239,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
}
|
||||
|
||||
/*if (AI_THINKING_STRUCT->aiFlags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI
|
||||
/*if (gAiThinkingStruct->aiFlags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI
|
||||
&& IsDoubleBattle()) //Make the regular AI know how to use Protect minimally in Doubles
|
||||
{
|
||||
u8 shouldProtect = ShouldProtect(battlerAtk, battlerDef, move);
|
||||
@ -2553,7 +2553,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
ADJUST_SCORE(-10);
|
||||
}
|
||||
else if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS))
|
||||
else if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS))
|
||||
{
|
||||
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM) // Trick Room Up
|
||||
{
|
||||
@ -2876,7 +2876,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
// Don't use a status move if the mon is the last one in the party, has no good switchin, or is trapped
|
||||
else if (GetBattleMoveCategory(move) == DAMAGE_CATEGORY_STATUS
|
||||
&& (CountUsablePartyMons(battlerAtk) < 1
|
||||
|| AI_DATA->mostSuitableMonId[battlerAtk] == PARTY_SIZE
|
||||
|| gAiLogicData->mostSuitableMonId[battlerAtk] == PARTY_SIZE
|
||||
|| (!AI_CanBattlerEscape(battlerAtk) && IsBattlerTrapped(battlerDef, battlerAtk))))
|
||||
ADJUST_SCORE(-30);
|
||||
}
|
||||
@ -2889,7 +2889,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|
||||
static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex;
|
||||
u32 movesetIndex = gAiThinkingStruct->movesetIndex;
|
||||
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||
return score;
|
||||
@ -2908,7 +2908,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
else if (CanTargetFaintAi(battlerDef, battlerAtk)
|
||||
&& GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) != AI_IS_FASTER
|
||||
&& GetBattleMovePriority(battlerAtk, AI_DATA->abilities[battlerAtk], move) > 0)
|
||||
&& GetBattleMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk], move) > 0)
|
||||
{
|
||||
ADJUST_SCORE(LAST_CHANCE);
|
||||
}
|
||||
@ -2925,14 +2925,14 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move);
|
||||
// ally data
|
||||
u32 battlerAtkPartner = BATTLE_PARTNER(battlerAtk);
|
||||
struct AiLogicData *aiData = AI_DATA;
|
||||
struct AiLogicData *aiData = gAiLogicData;
|
||||
u32 atkPartnerAbility = aiData->abilities[BATTLE_PARTNER(battlerAtk)];
|
||||
u32 atkPartnerHoldEffect = aiData->holdEffects[BATTLE_PARTNER(battlerAtk)];
|
||||
enum BattleMoveEffects partnerEffect = GetMoveEffect(aiData->partnerMove);
|
||||
bool32 partnerProtecting = (partnerEffect == EFFECT_PROTECT);
|
||||
bool32 attackerHasBadAbility = (gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating < 0);
|
||||
bool32 partnerHasBadAbility = (gAbilitiesInfo[atkPartnerAbility].aiRating < 0);
|
||||
u32 predictedMove = ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? AI_DATA->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
|
||||
u32 predictedMove = ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? gAiLogicData->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
|
||||
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
moveType = GetBattleMoveType(move);
|
||||
@ -3066,13 +3066,13 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (MoveAlwaysCrits(move)
|
||||
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)
|
||||
&& AI_IsFaster(battlerAtk, battlerAtkPartner, move)
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING))
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, gAiThinkingStruct->movesetIndex, AI_ATTACKING))
|
||||
{
|
||||
RETURN_SCORE_PLUS(GOOD_EFFECT);
|
||||
}
|
||||
break;
|
||||
case ABILITY_VOLT_ABSORB:
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE))
|
||||
if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE))
|
||||
{
|
||||
RETURN_SCORE_MINUS(10);
|
||||
}
|
||||
@ -3095,7 +3095,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case ABILITY_WATER_ABSORB:
|
||||
case ABILITY_DRY_SKIN:
|
||||
case ABILITY_EARTH_EATER:
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE))
|
||||
if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE))
|
||||
{
|
||||
RETURN_SCORE_MINUS(10);
|
||||
}
|
||||
@ -3110,7 +3110,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
break;
|
||||
case ABILITY_WATER_COMPACTION:
|
||||
if (moveType == TYPE_WATER && GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING) >= 4)
|
||||
if (moveType == TYPE_WATER && GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING) >= 4)
|
||||
{
|
||||
RETURN_SCORE_PLUS(WEAK_EFFECT); // only mon with this ability is weak to water so only make it okay if we do very little damage
|
||||
}
|
||||
@ -3137,7 +3137,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
&& !IsBattleMoveStatus(move)
|
||||
&& HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL)
|
||||
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING))
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, gAiThinkingStruct->movesetIndex, AI_ATTACKING))
|
||||
{
|
||||
RETURN_SCORE_PLUS(WEAK_EFFECT);
|
||||
}
|
||||
@ -3146,7 +3146,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (!IsBattleMoveStatus(move)
|
||||
&& (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG)
|
||||
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED)
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING))
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, gAiThinkingStruct->movesetIndex, AI_ATTACKING))
|
||||
{
|
||||
RETURN_SCORE_PLUS(WEAK_EFFECT);
|
||||
}
|
||||
@ -3203,7 +3203,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
&& !IsBattleMoveStatus(move)
|
||||
&& HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL)
|
||||
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING))
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, gAiThinkingStruct->movesetIndex, AI_ATTACKING))
|
||||
{
|
||||
RETURN_SCORE_PLUS(WEAK_EFFECT);
|
||||
}
|
||||
@ -3342,8 +3342,8 @@ static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect)
|
||||
|
||||
static s32 CompareMoveAccuracies(u32 battlerAtk, u32 battlerDef, u32 moveSlot1, u32 moveSlot2)
|
||||
{
|
||||
u32 acc1 = AI_DATA->moveAccuracy[battlerAtk][battlerDef][moveSlot1];
|
||||
u32 acc2 = AI_DATA->moveAccuracy[battlerAtk][battlerDef][moveSlot2];
|
||||
u32 acc1 = gAiLogicData->moveAccuracy[battlerAtk][battlerDef][moveSlot1];
|
||||
u32 acc2 = gAiLogicData->moveAccuracy[battlerAtk][battlerDef][moveSlot2];
|
||||
|
||||
if (acc1 > acc2)
|
||||
return 1;
|
||||
@ -3466,7 +3466,7 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId)
|
||||
|
||||
static u32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
struct AiLogicData *aiData = AI_DATA;
|
||||
struct AiLogicData *aiData = gAiLogicData;
|
||||
enum ItemHoldEffect holdEffect = aiData->holdEffects[battlerAtk];
|
||||
|
||||
s32 score = 0;
|
||||
@ -3475,7 +3475,7 @@ static u32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
case HOLD_EFFECT_BLUNDER_POLICY:
|
||||
{
|
||||
u32 moveAcc = aiData->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
|
||||
u32 moveAcc = aiData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex];
|
||||
|
||||
if (moveAcc <= LOW_ACCURACY_THRESHOLD)
|
||||
{
|
||||
@ -3498,12 +3498,12 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
// move data
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
struct AiLogicData *aiData = AI_DATA;
|
||||
u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex;
|
||||
struct AiLogicData *aiData = gAiLogicData;
|
||||
u32 movesetIndex = gAiThinkingStruct->movesetIndex;
|
||||
uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex];
|
||||
|
||||
s32 score = 0;
|
||||
u32 predictedMove = ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? AI_DATA->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
|
||||
u32 predictedMove = ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? gAiLogicData->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
|
||||
u32 predictedType = GetMoveType(predictedMove);
|
||||
u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove);
|
||||
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
|
||||
@ -3514,7 +3514,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
moveEffect = EFFECT_PROTECT;
|
||||
|
||||
// check status move preference
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IsBattleMoveStatus(move) && effectiveness != UQ_4_12(0.0))
|
||||
if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IsBattleMoveStatus(move) && effectiveness != UQ_4_12(0.0))
|
||||
ADJUST_SCORE(10);
|
||||
|
||||
// check thawing moves
|
||||
@ -3522,7 +3522,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(10);
|
||||
|
||||
// check burn / frostbite
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && AI_DATA->abilities[battlerAtk] == ABILITY_NATURAL_CURE)
|
||||
if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && gAiLogicData->abilities[battlerAtk] == ABILITY_NATURAL_CURE)
|
||||
{
|
||||
if ((gBattleMons[battlerAtk].status1 & STATUS1_BURN && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL, TRUE))
|
||||
|| (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL, TRUE)))
|
||||
@ -3548,14 +3548,14 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
break;
|
||||
case EFFECT_EXPLOSION:
|
||||
case EFFECT_MEMENTO:
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7)
|
||||
if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7)
|
||||
{
|
||||
if (aiData->hpPercents[battlerAtk] < 50 && AI_RandLessThan(128))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
}
|
||||
break;
|
||||
case EFFECT_FINAL_GAMBIT:
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE)
|
||||
if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_MIRROR_MOVE:
|
||||
@ -3884,7 +3884,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
break;
|
||||
case EFFECT_BATON_PASS:
|
||||
if ((AI_DATA->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE
|
||||
if ((gAiLogicData->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE
|
||||
|| (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING | STATUS3_MAGNET_RISE | STATUS3_POWER_TRICK))
|
||||
|| AnyStatIsRaised(battlerAtk)))
|
||||
ADJUST_SCORE(BEST_EFFECT);
|
||||
@ -4568,7 +4568,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(GOOD_EFFECT); // Partner might use pledge move
|
||||
break;
|
||||
case EFFECT_TRICK_ROOM:
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS))
|
||||
if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS))
|
||||
{
|
||||
if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
@ -4737,9 +4737,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
if (GetFirstFaintedPartyIndex(battlerAtk) != PARTY_SIZE)
|
||||
{
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
if (AI_DATA->shouldSwitch & (1u << battlerAtk)) // Bad matchup
|
||||
if (gAiLogicData->shouldSwitch & (1u << battlerAtk)) // Bad matchup
|
||||
ADJUST_SCORE(WEAK_EFFECT);
|
||||
if (AI_DATA->mostSuitableMonId[battlerAtk] != PARTY_SIZE) // Good mon to send in after
|
||||
if (gAiLogicData->mostSuitableMonId[battlerAtk] != PARTY_SIZE) // Good mon to send in after
|
||||
ADJUST_SCORE(WEAK_EFFECT);
|
||||
}
|
||||
break;
|
||||
@ -5026,15 +5026,15 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
||||
|
||||
if (GetMovePower(move) != 0)
|
||||
{
|
||||
if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING) == 0)
|
||||
if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING) == 0)
|
||||
ADJUST_AND_RETURN_SCORE(NO_DAMAGE_OR_FAILS); // No point in checking the move further so return early
|
||||
else
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & (AI_FLAG_RISKY | AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE)
|
||||
if (gAiThinkingStruct->aiFlags[battlerAtk] & (AI_FLAG_RISKY | AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE)
|
||||
&& GetBestDmgMoveFromBattler(battlerAtk, battlerDef, AI_ATTACKING) == move)
|
||||
ADJUST_SCORE(BEST_DAMAGE_MOVE);
|
||||
else
|
||||
ADJUST_SCORE(AI_CompareDamagingMoves(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex));
|
||||
ADJUST_SCORE(AI_CompareDamagingMoves(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5052,10 +5052,10 @@ static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32
|
||||
|| gBattleResults.battleTurnCounter != 0)
|
||||
return score;
|
||||
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING
|
||||
if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING
|
||||
&& AI_IsSlower(battlerAtk, battlerDef, move)
|
||||
&& CanTargetFaintAi(battlerDef, battlerAtk)
|
||||
&& GetBattleMovePriority(battlerAtk, AI_DATA->abilities[battlerAtk], move) == 0)
|
||||
&& GetBattleMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk], move) == 0)
|
||||
{
|
||||
RETURN_SCORE_MINUS(20); // No point in setting up if you will faint. Should just switch if possible..
|
||||
}
|
||||
@ -5179,7 +5179,7 @@ static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32
|
||||
static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
u8 i;
|
||||
struct AiLogicData *aiData = AI_DATA;
|
||||
struct AiLogicData *aiData = gAiLogicData;
|
||||
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||
return score;
|
||||
@ -5255,9 +5255,9 @@ static s32 AI_TryTo2HKO(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||
return score;
|
||||
|
||||
if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING) == 1)
|
||||
if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING) == 1)
|
||||
ADJUST_SCORE(BEST_EFFECT);
|
||||
else if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING) == 2)
|
||||
else if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING) == 2)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
|
||||
return score;
|
||||
@ -5279,7 +5279,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor
|
||||
{
|
||||
if (gBattleResults.battleTurnCounter == 0)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
else if (AI_DATA->hpPercents[battlerAtk] < 60)
|
||||
else if (gAiLogicData->hpPercents[battlerAtk] < 60)
|
||||
ADJUST_SCORE(-10);
|
||||
else
|
||||
ADJUST_SCORE(WEAK_EFFECT);
|
||||
@ -5327,9 +5327,9 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||
{
|
||||
if ((effect == EFFECT_HEAL_PULSE || effect == EFFECT_HIT_ENEMY_HEAL_ALLY)
|
||||
|| (moveType == TYPE_ELECTRIC && AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_VOLT_ABSORB)
|
||||
|| (moveType == TYPE_GROUND && AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_EARTH_EATER)
|
||||
|| (moveType == TYPE_WATER && (AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_DRY_SKIN || AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_WATER_ABSORB)))
|
||||
|| (moveType == TYPE_ELECTRIC && gAiLogicData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_VOLT_ABSORB)
|
||||
|| (moveType == TYPE_GROUND && gAiLogicData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_EARTH_EATER)
|
||||
|| (moveType == TYPE_WATER && (gAiLogicData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_DRY_SKIN || gAiLogicData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_WATER_ABSORB)))
|
||||
{
|
||||
if (gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK)
|
||||
return 0;
|
||||
@ -5338,14 +5338,14 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|| (CanTargetFaintAi(BATTLE_PARTNER(FOE(battlerAtk)), BATTLE_PARTNER(battlerAtk))))
|
||||
ADJUST_SCORE(-1);
|
||||
|
||||
if (AI_DATA->hpPercents[battlerDef] <= 50)
|
||||
if (gAiLogicData->hpPercents[battlerDef] <= 50)
|
||||
ADJUST_SCORE(WEAK_EFFECT);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Consider AI HP
|
||||
if (AI_DATA->hpPercents[battlerAtk] > 70)
|
||||
if (gAiLogicData->hpPercents[battlerAtk] > 70)
|
||||
{
|
||||
// high hp
|
||||
switch (effect)
|
||||
@ -5370,7 +5370,7 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (AI_DATA->hpPercents[battlerAtk] > 30)
|
||||
else if (gAiLogicData->hpPercents[battlerAtk] > 30)
|
||||
{
|
||||
// med hp
|
||||
if (IsStatRaisingEffect(effect) || IsStatLoweringEffect(effect))
|
||||
@ -5433,18 +5433,18 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
|
||||
// consider target HP
|
||||
if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING))
|
||||
if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING))
|
||||
{
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AI_DATA->hpPercents[battlerDef] > 70)
|
||||
if (gAiLogicData->hpPercents[battlerDef] > 70)
|
||||
{
|
||||
// high HP
|
||||
; // nothing yet
|
||||
}
|
||||
else if (AI_DATA->hpPercents[battlerDef] > 30)
|
||||
else if (gAiLogicData->hpPercents[battlerDef] > 30)
|
||||
{
|
||||
// med HP - check discouraged effects
|
||||
switch (effect)
|
||||
@ -5512,7 +5512,7 @@ static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
||||
{
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
|
||||
if (GetMoveCategory(move) != DAMAGE_CATEGORY_STATUS || GetMoveEffect(AI_DATA->partnerMove) == moveEffect)
|
||||
if (GetMoveCategory(move) != DAMAGE_CATEGORY_STATUS || GetMoveEffect(gAiLogicData->partnerMove) == moveEffect)
|
||||
return score;
|
||||
|
||||
switch (moveEffect)
|
||||
@ -5555,7 +5555,7 @@ static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
||||
case EFFECT_STEALTH_ROCK:
|
||||
case EFFECT_STICKY_WEB:
|
||||
case EFFECT_TOXIC_SPIKES:
|
||||
if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, AI_DATA))
|
||||
if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, gAiLogicData))
|
||||
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
|
||||
break;
|
||||
case EFFECT_GRASSY_TERRAIN:
|
||||
@ -5609,16 +5609,16 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
u32 opposingHazardFlags = gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_TOXIC_SPIKES);
|
||||
u32 aiHazardFlags = gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_HAZARDS_ANY);
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
struct AiLogicData *aiData = AI_DATA;
|
||||
uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
|
||||
u32 predictedMove = ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? AI_DATA->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
|
||||
struct AiLogicData *aiData = gAiLogicData;
|
||||
uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex];
|
||||
u32 predictedMove = ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? aiData->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
|
||||
|
||||
// Switch benefit
|
||||
switch (moveEffect)
|
||||
{
|
||||
case EFFECT_PURSUIT:
|
||||
{
|
||||
u32 hitsToKO = GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING);
|
||||
u32 hitsToKO = GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING);
|
||||
if (hitsToKO == 2)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
else if (hitsToKO == 1)
|
||||
@ -5630,7 +5630,7 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|
||||
case EFFECT_FOCUS_PUNCH:
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CHECK_BAD_MOVE)
|
||||
if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CHECK_BAD_MOVE)
|
||||
{
|
||||
if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < UQ_4_12(2.0))
|
||||
ADJUST_SCORE(10);
|
||||
@ -5691,7 +5691,7 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_RESTORE_HP:
|
||||
if (AI_DATA->hpPercents[battlerAtk] < 60)
|
||||
if (gAiLogicData->hpPercents[battlerAtk] < 60)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
|
||||
@ -5764,12 +5764,12 @@ static s32 AI_CheckPpStall(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|
||||
static void AI_Flee(void)
|
||||
{
|
||||
AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK);
|
||||
gAiThinkingStruct->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK);
|
||||
}
|
||||
|
||||
static void AI_Watch(void)
|
||||
{
|
||||
AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK);
|
||||
gAiThinkingStruct->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK);
|
||||
}
|
||||
|
||||
// Roaming pokemon logic
|
||||
@ -5779,9 +5779,9 @@ static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|
||||
if (AI_CanBattlerEscape(battlerAtk))
|
||||
roamerCanFlee = TRUE;
|
||||
else if (AI_DATA->abilities[battlerAtk] == ABILITY_RUN_AWAY)
|
||||
else if (gAiLogicData->abilities[battlerAtk] == ABILITY_RUN_AWAY)
|
||||
roamerCanFlee = TRUE;
|
||||
else if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CAN_ALWAYS_RUN)
|
||||
else if (gAiLogicData->holdEffects[battlerAtk] == HOLD_EFFECT_CAN_ALWAYS_RUN)
|
||||
roamerCanFlee = TRUE;
|
||||
|
||||
if (!roamerCanFlee && IsBattlerTrapped(battlerDef, battlerAtk))
|
||||
@ -5807,7 +5807,7 @@ static s32 AI_Safari(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
// First battle logic
|
||||
static s32 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
if (AI_DATA->hpPercents[battlerDef] <= 20)
|
||||
if (gAiLogicData->hpPercents[battlerDef] <= 20)
|
||||
AI_Flee();
|
||||
|
||||
return score;
|
||||
|
||||
@ -34,8 +34,8 @@ static u32 GetHPHealAmount(u8 itemEffectParam, struct Pokemon *mon);
|
||||
|
||||
static void InitializeSwitchinCandidate(struct Pokemon *mon)
|
||||
{
|
||||
PokemonToBattleMon(mon, &AI_DATA->switchinCandidate.battleMon);
|
||||
AI_DATA->switchinCandidate.hypotheticalStatus = FALSE;
|
||||
PokemonToBattleMon(mon, &gAiLogicData->switchinCandidate.battleMon);
|
||||
gAiLogicData->switchinCandidate.hypotheticalStatus = FALSE;
|
||||
}
|
||||
|
||||
u32 GetSwitchChance(enum ShouldSwitchScenario shouldSwitchScenario)
|
||||
@ -110,11 +110,11 @@ u32 GetSwitchChance(enum ShouldSwitchScenario shouldSwitchScenario)
|
||||
|
||||
static bool32 IsAceMon(u32 battler, u32 monPartyId)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_ACE_POKEMON
|
||||
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_ACE_POKEMON
|
||||
&& !gBattleStruct->battlerState[battler].forcedSwitch
|
||||
&& monPartyId == CalculateEnemyPartyCountInSide(battler)-1)
|
||||
return TRUE;
|
||||
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_DOUBLE_ACE_POKEMON
|
||||
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_DOUBLE_ACE_POKEMON
|
||||
&& !gBattleStruct->battlerState[battler].forcedSwitch
|
||||
&& (monPartyId == CalculateEnemyPartyCount()-1 || monPartyId == CalculateEnemyPartyCount()-2))
|
||||
return TRUE;
|
||||
@ -163,7 +163,7 @@ static inline bool32 SetSwitchinAndSwitch(u32 battler, u32 switchinId)
|
||||
static bool32 AI_DoesChoiceItemBlockMove(u32 battler, u32 move)
|
||||
{
|
||||
// Choice locked into something else
|
||||
if (AI_DATA->lastUsedMove[battler] != MOVE_NONE && AI_DATA->lastUsedMove[battler] != move && HOLD_EFFECT_CHOICE(GetBattlerHoldEffect(battler, FALSE)) && IsBattlerItemEnabled(battler))
|
||||
if (gAiLogicData->lastUsedMove[battler] != MOVE_NONE && gAiLogicData->lastUsedMove[battler] != move && HOLD_EFFECT_CHOICE(GetBattlerHoldEffect(battler, FALSE)) && IsBattlerItemEnabled(battler))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
@ -176,13 +176,13 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
//Variable initialization
|
||||
u8 opposingPosition, atkType1, atkType2, defType1, defType2;
|
||||
s32 i, damageDealt = 0, maxDamageDealt = 0, damageTaken = 0, maxDamageTaken = 0;
|
||||
u32 aiMove, playerMove, aiBestMove = MOVE_NONE, aiAbility = AI_DATA->abilities[battler], opposingBattler;
|
||||
u32 aiMove, playerMove, aiBestMove = MOVE_NONE, aiAbility = gAiLogicData->abilities[battler], opposingBattler;
|
||||
bool32 getsOneShot = FALSE, hasStatusMove = FALSE, hasSuperEffectiveMove = FALSE;
|
||||
u16 typeEffectiveness = UQ_4_12(1.0); //baseline typing damage
|
||||
enum BattleMoveEffects aiMoveEffect;
|
||||
|
||||
// Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
// Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic
|
||||
@ -223,7 +223,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
hasSuperEffectiveMove = TRUE;
|
||||
|
||||
// Get maximum damage mon can deal
|
||||
damageDealt = AI_GetDamage(battler, opposingBattler, i, AI_ATTACKING, AI_DATA);
|
||||
damageDealt = AI_GetDamage(battler, opposingBattler, i, AI_ATTACKING, gAiLogicData);
|
||||
if(damageDealt > maxDamageDealt && !AI_DoesChoiceItemBlockMove(battler, aiMove))
|
||||
{
|
||||
maxDamageDealt = damageDealt;
|
||||
@ -250,7 +250,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
playerMove = gBattleMons[opposingBattler].moves[i];
|
||||
if (playerMove != MOVE_NONE && !IsBattleMoveStatus(playerMove) && GetMoveEffect(playerMove) != EFFECT_FOCUS_PUNCH)
|
||||
{
|
||||
damageTaken = AI_GetDamage(opposingBattler, battler, i, AI_DEFENDING, AI_DATA);
|
||||
damageTaken = AI_GetDamage(opposingBattler, battler, i, AI_DEFENDING, gAiLogicData);
|
||||
if (playerMove == gBattleStruct->choicedMove[opposingBattler]) // If player is choiced, only care about the choice locked move
|
||||
{
|
||||
return maxDamageTaken = damageTaken;
|
||||
@ -276,7 +276,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
}
|
||||
|
||||
// If we don't have any other viable options, don't switch out
|
||||
if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE)
|
||||
if (gAiLogicData->mostSuitableMonId[battler] == PARTY_SIZE)
|
||||
return FALSE;
|
||||
|
||||
// Start assessing whether or not mon has bad odds
|
||||
@ -288,7 +288,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4)))
|
||||
{
|
||||
// 50% chance to stay in regardless
|
||||
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !AI_DATA->aiPredictionInProgress)
|
||||
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !gAiLogicData->aiPredictionInProgress)
|
||||
return FALSE;
|
||||
|
||||
// Switch mon out
|
||||
@ -308,7 +308,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
return FALSE;
|
||||
|
||||
// 50% chance to stay in regardless
|
||||
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !AI_DATA->aiPredictionInProgress)
|
||||
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !gAiLogicData->aiPredictionInProgress)
|
||||
return FALSE;
|
||||
|
||||
// Switch mon out
|
||||
@ -321,11 +321,11 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
static bool32 ShouldSwitchIfTruant(u32 battler)
|
||||
{
|
||||
// Switch if mon with truant is bodied by Protect or invulnerability spam
|
||||
if (AI_DATA->abilities[battler] == ABILITY_TRUANT
|
||||
if (gAiLogicData->abilities[battler] == ABILITY_TRUANT
|
||||
&& IsTruantMonVulnerable(battler, gBattlerTarget)
|
||||
&& gDisableStructs[battler].truantCounter
|
||||
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2
|
||||
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
|
||||
&& gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE)
|
||||
{
|
||||
if (RandomPercentage(RNG_AI_SWITCH_TRUANT, GetSwitchChance(SHOULD_SWITCH_TRUANT)))
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
@ -397,7 +397,7 @@ static bool32 ShouldSwitchIfAllMovesBad(u32 battler)
|
||||
|
||||
if (RandomPercentage(RNG_AI_SWITCH_ALL_MOVES_BAD, GetSwitchChance(SHOULD_SWITCH_ALL_MOVES_BAD)))
|
||||
{
|
||||
if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE) // No good candidate mons, find any one that can deal damage
|
||||
if (gAiLogicData->mostSuitableMonId[battler] == PARTY_SIZE) // No good candidate mons, find any one that can deal damage
|
||||
return FindMonWithMoveOfEffectiveness(battler, opposingBattler, UQ_4_12(1.0));
|
||||
else // Good candidate mon, send that in
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
@ -414,7 +414,7 @@ static bool32 ShouldSwitchIfWonderGuard(u32 battler)
|
||||
if (IsDoubleBattle())
|
||||
return FALSE;
|
||||
|
||||
if (AI_DATA->abilities[opposingBattler] != ABILITY_WONDER_GUARD)
|
||||
if (gAiLogicData->abilities[opposingBattler] != ABILITY_WONDER_GUARD)
|
||||
return FALSE;
|
||||
|
||||
// Check if Pokémon has a super effective move.
|
||||
@ -430,7 +430,7 @@ static bool32 ShouldSwitchIfWonderGuard(u32 battler)
|
||||
|
||||
if (RandomPercentage(RNG_AI_SWITCH_WONDER_GUARD, GetSwitchChance(SHOULD_SWITCH_WONDER_GUARD)))
|
||||
{
|
||||
if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE) // No good candidate mons, find any one that can deal damage
|
||||
if (gAiLogicData->mostSuitableMonId[battler] == PARTY_SIZE) // No good candidate mons, find any one that can deal damage
|
||||
return FindMonWithMoveOfEffectiveness(battler, opposingBattler, UQ_4_12(2.0));
|
||||
else // Good candidate mon, send that in
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
@ -449,16 +449,16 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
|
||||
struct Pokemon *party;
|
||||
u16 monAbility, aiMove;
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
u32 incomingMove = ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVE) && AI_DATA->predictingMove) ? AI_DATA->predictedMove[opposingBattler] : AI_DATA->lastUsedMove[opposingBattler];
|
||||
u32 incomingMove = ((gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_MOVE) && gAiLogicData->predictingMove) ? gAiLogicData->predictedMove[opposingBattler] : gAiLogicData->lastUsedMove[opposingBattler];
|
||||
u32 incomingType = GetMoveType(incomingMove);
|
||||
bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove));
|
||||
s32 i, j;
|
||||
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
if (gBattleStruct->prevTurnSpecies[battler] != gBattleMons[battler].species && !(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVE)) // AI mon has changed, player's behaviour no longer reliable; override this if using AI_FLAG_PREDICT_MOVE
|
||||
if (gBattleStruct->prevTurnSpecies[battler] != gBattleMons[battler].species && !(gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_MOVE)) // AI mon has changed, player's behaviour no longer reliable; override this if using AI_FLAG_PREDICT_MOVE
|
||||
return FALSE;
|
||||
if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING_STAY_IN, STAY_IN_ABSORBING_PERCENTAGE) || AI_DATA->aiPredictionInProgress))
|
||||
if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING_STAY_IN, STAY_IN_ABSORBING_PERCENTAGE) || gAiLogicData->aiPredictionInProgress))
|
||||
return FALSE;
|
||||
if (AreStatsRaised(battler))
|
||||
return FALSE;
|
||||
@ -472,7 +472,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
|
||||
// Only check damage if it's a damaging move
|
||||
if (!IsBattleMoveStatus(aiMove))
|
||||
{
|
||||
if (AI_GetDamage(battler, opposingBattler, i, AI_ATTACKING, AI_DATA) > gBattleMons[opposingBattler].hp)
|
||||
if (AI_GetDamage(battler, opposingBattler, i, AI_ATTACKING, gAiLogicData) > gBattleMons[opposingBattler].hp)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@ -574,13 +574,13 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
|
||||
static bool32 ShouldSwitchIfOpponentChargingOrInvulnerable(u32 battler)
|
||||
{
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
u32 incomingMove = ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVE) && AI_DATA->predictingMove) ? AI_DATA->predictedMove[opposingBattler] : AI_DATA->lastUsedMove[opposingBattler];
|
||||
u32 incomingMove = ((gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_MOVE) && gAiLogicData->predictingMove) ? gAiLogicData->predictedMove[opposingBattler] : gAiLogicData->lastUsedMove[opposingBattler];
|
||||
bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove));
|
||||
|
||||
if (IsDoubleBattle() || !(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
if (IsDoubleBattle() || !(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
if (isOpposingBattlerChargingOrInvulnerable && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN)))
|
||||
if (isOpposingBattlerChargingOrInvulnerable && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN)))
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
|
||||
return FALSE;
|
||||
@ -596,7 +596,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler)
|
||||
s32 opposingBattler = GetOppositeBattler(battler);
|
||||
|
||||
// Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
// Check if current mon has an ability that traps opponent
|
||||
@ -617,7 +617,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler)
|
||||
if (CanAbilityTrapOpponent(monAbility, opposingBattler) || (CanAbilityTrapOpponent(AI_GetBattlerAbility(opposingBattler), opposingBattler) && monAbility == ABILITY_TRACE))
|
||||
{
|
||||
// If mon in slot i is the most suitable switchin candidate, then it's a trapper than wins 1v1
|
||||
if (i == AI_DATA->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN)))
|
||||
if (i == gAiLogicData->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN)))
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
}
|
||||
}
|
||||
@ -627,8 +627,8 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler)
|
||||
static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
|
||||
{
|
||||
bool32 switchMon = FALSE;
|
||||
u16 monAbility = AI_DATA->abilities[battler];
|
||||
enum ItemHoldEffect holdEffect = AI_DATA->holdEffects[battler];
|
||||
u16 monAbility = gAiLogicData->abilities[battler];
|
||||
enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battler];
|
||||
u8 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler));
|
||||
u8 opposingBattler = GetBattlerAtPosition(opposingPosition);
|
||||
bool32 hasStatRaised = AnyStatIsRaised(battler);
|
||||
@ -640,7 +640,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
|
||||
&& RandomPercentage(RNG_AI_SWITCH_PERISH_SONG, GetSwitchChance(SHOULD_SWITCH_PERISH_SONG)))
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
|
||||
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)
|
||||
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)
|
||||
{
|
||||
//Yawn
|
||||
if (gStatuses3[battler] & STATUS3_YAWN
|
||||
@ -651,7 +651,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
|
||||
switchMon = TRUE;
|
||||
|
||||
// If we don't have a good switchin, not worth switching
|
||||
if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE)
|
||||
if (gAiLogicData->mostSuitableMonId[battler] == PARTY_SIZE)
|
||||
switchMon = FALSE;
|
||||
|
||||
// Check if Active Pokemon can KO opponent instead of switching
|
||||
@ -673,10 +673,10 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
|
||||
|
||||
// Check if Active Pokemon evasion boosted and might be able to dodge until awake
|
||||
if (gBattleMons[battler].statStages[STAT_EVASION] > (DEFAULT_STAT_STAGE + 3)
|
||||
&& AI_DATA->abilities[opposingBattler] != ABILITY_UNAWARE
|
||||
&& AI_DATA->abilities[opposingBattler] != ABILITY_KEEN_EYE
|
||||
&& AI_DATA->abilities[opposingBattler] != ABILITY_MINDS_EYE
|
||||
&& (B_ILLUMINATE_EFFECT >= GEN_9 && AI_DATA->abilities[opposingBattler] != ABILITY_ILLUMINATE)
|
||||
&& gAiLogicData->abilities[opposingBattler] != ABILITY_UNAWARE
|
||||
&& gAiLogicData->abilities[opposingBattler] != ABILITY_KEEN_EYE
|
||||
&& gAiLogicData->abilities[opposingBattler] != ABILITY_MINDS_EYE
|
||||
&& (B_ILLUMINATE_EFFECT >= GEN_9 && gAiLogicData->abilities[opposingBattler] != ABILITY_ILLUMINATE)
|
||||
&& !(gBattleMons[battler].status2 & STATUS2_FORESIGHT)
|
||||
&& !(gStatuses3[battler] & STATUS3_MIRACLE_EYED))
|
||||
switchMon = FALSE;
|
||||
@ -688,12 +688,12 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
|
||||
// Secondary Damage
|
||||
if (monAbility != ABILITY_MAGIC_GUARD
|
||||
&& !AiExpectsToFaintPlayer(battler)
|
||||
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
|
||||
&& gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE)
|
||||
{
|
||||
//Toxic
|
||||
if (((gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >= STATUS1_TOXIC_TURN(2))
|
||||
&& gBattleMons[battler].hp >= (gBattleMons[battler].maxHP / 3)
|
||||
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, GetSwitchChance(SHOULD_SWITCH_BADLY_POISONED_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, GetSwitchChance(SHOULD_SWITCH_BADLY_POISONED))))
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
|
||||
@ -716,7 +716,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
|
||||
// Infatuation
|
||||
if (gBattleMons[battler].status2 & STATUS2_INFATUATION
|
||||
&& !AiExpectsToFaintPlayer(battler)
|
||||
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& RandomPercentage(RNG_AI_SWITCH_INFATUATION, GetSwitchChance(SHOULD_SWITCH_INFATUATION)))
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
}
|
||||
@ -733,18 +733,18 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler)
|
||||
|| IsNeutralizingGasOnField())
|
||||
return FALSE;
|
||||
|
||||
switch(AI_DATA->abilities[battler])
|
||||
switch(gAiLogicData->abilities[battler])
|
||||
{
|
||||
case ABILITY_NATURAL_CURE:
|
||||
//Attempt to cure bad ailment
|
||||
if (gBattleMons[battler].status1 & (STATUS1_SLEEP | STATUS1_FREEZE | STATUS1_TOXIC_POISON)
|
||||
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_STRONG_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_STRONG))))
|
||||
break;
|
||||
//Attempt to cure lesser ailment
|
||||
if ((gBattleMons[battler].status1 & STATUS1_ANY)
|
||||
&& (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2)
|
||||
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_WEAK_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_WEAK))))
|
||||
break;
|
||||
|
||||
@ -755,12 +755,12 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler)
|
||||
if (gBattleMons[battler].status1 & STATUS1_ANY)
|
||||
return FALSE;
|
||||
if ((gBattleMons[battler].hp <= ((gBattleMons[battler].maxHP * 2) / 3))
|
||||
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE
|
||||
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_REGENERATOR, GetSwitchChance(SHOULD_SWITCH_REGENERATOR_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_REGENERATOR, GetSwitchChance(SHOULD_SWITCH_REGENERATOR))))
|
||||
break;
|
||||
|
||||
return FALSE;
|
||||
|
||||
|
||||
case ABILITY_ZERO_TO_HERO:
|
||||
// Want to activate Palafin-Zero at all costs
|
||||
if (gBattleMons[battler].species == SPECIES_PALAFIN_ZERO)
|
||||
@ -834,7 +834,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc
|
||||
u16 move;
|
||||
|
||||
// Similar functionality handled more thoroughly by ShouldSwitchIfHasBadOdds
|
||||
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)
|
||||
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)
|
||||
return FALSE;
|
||||
|
||||
if (gLastLandedMoves[battler] == MOVE_NONE)
|
||||
@ -896,7 +896,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc
|
||||
if (move == 0)
|
||||
continue;
|
||||
|
||||
if (AI_GetMoveEffectiveness(move, battler, battlerIn1) >= UQ_4_12(2.0) && (RandomPercentage(RNG_AI_SWITCH_SE_DEFENSIVE, percentChance) || AI_DATA->aiPredictionInProgress))
|
||||
if (AI_GetMoveEffectiveness(move, battler, battlerIn1) >= UQ_4_12(2.0) && (RandomPercentage(RNG_AI_SWITCH_SE_DEFENSIVE, percentChance) || gAiLogicData->aiPredictionInProgress))
|
||||
return SetSwitchinAndSwitch(battler, i);
|
||||
}
|
||||
}
|
||||
@ -909,7 +909,7 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler)
|
||||
{
|
||||
u32 battlerIn1, battlerIn2;
|
||||
u32 hazardDamage = 0, battlerHp = gBattleMons[battler].hp;
|
||||
u32 ability = AI_DATA->abilities[battler], aiMove;
|
||||
u32 ability = gAiLogicData->abilities[battler], aiMove;
|
||||
s32 firstId, lastId, i, j;
|
||||
struct Pokemon *party;
|
||||
|
||||
@ -972,7 +972,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler)
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
|
||||
// Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
// If not Encore'd don't switch
|
||||
@ -988,7 +988,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler)
|
||||
return FALSE;
|
||||
|
||||
// Switch out 50% of the time otherwise
|
||||
else if ((RandomPercentage(RNG_AI_SWITCH_ENCORE, GetSwitchChance(SHOULD_SWITCH_ENCORE_DAMAGE)) || AI_DATA->aiPredictionInProgress) && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
|
||||
else if ((RandomPercentage(RNG_AI_SWITCH_ENCORE, GetSwitchChance(SHOULD_SWITCH_ENCORE_DAMAGE)) || gAiLogicData->aiPredictionInProgress) && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE)
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
|
||||
return FALSE;
|
||||
@ -997,13 +997,13 @@ static bool32 ShouldSwitchIfEncored(u32 battler)
|
||||
static bool32 ShouldSwitchIfBadChoiceLock(u32 battler)
|
||||
{
|
||||
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE);
|
||||
u32 lastUsedMove = AI_DATA->lastUsedMove[battler];
|
||||
u32 lastUsedMove = gAiLogicData->lastUsedMove[battler];
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
bool32 moveAffectsTarget = TRUE;
|
||||
|
||||
if (lastUsedMove != MOVE_NONE && (AI_GetMoveEffectiveness(lastUsedMove, battler, opposingBattler) == UQ_4_12(0.0)
|
||||
|| CanAbilityAbsorbMove(battler, opposingBattler, AI_DATA->abilities[opposingBattler], lastUsedMove, GetMoveType(lastUsedMove), ABILITY_CHECK_TRIGGER)
|
||||
|| CanAbilityBlockMove(battler, opposingBattler, AI_DATA->abilities[battler], AI_DATA->abilities[opposingBattler], lastUsedMove, ABILITY_CHECK_TRIGGER)))
|
||||
|| CanAbilityAbsorbMove(battler, opposingBattler, gAiLogicData->abilities[opposingBattler], lastUsedMove, GetMoveType(lastUsedMove), ABILITY_CHECK_TRIGGER)
|
||||
|| CanAbilityBlockMove(battler, opposingBattler, gAiLogicData->abilities[battler], gAiLogicData->abilities[opposingBattler], lastUsedMove, ABILITY_CHECK_TRIGGER)))
|
||||
moveAffectsTarget = FALSE;
|
||||
|
||||
if (HOLD_EFFECT_CHOICE(holdEffect) && IsBattlerItemEnabled(battler))
|
||||
@ -1022,7 +1022,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler)
|
||||
s8 spAttackingStage = gBattleMons[battler].statStages[STAT_SPATK];
|
||||
|
||||
// Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
// Physical attacker
|
||||
@ -1034,7 +1034,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler)
|
||||
// 50% chance if attack at -2 and have a good candidate mon
|
||||
else if (attackingStage == DEFAULT_STAT_STAGE - 2)
|
||||
{
|
||||
if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || AI_DATA->aiPredictionInProgress))
|
||||
if (gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || gAiLogicData->aiPredictionInProgress))
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
}
|
||||
// If at -3 or worse, switch out regardless
|
||||
@ -1051,7 +1051,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler)
|
||||
// 50% chance if attack at -2 and have a good candidate mon
|
||||
else if (spAttackingStage == DEFAULT_STAT_STAGE - 2)
|
||||
{
|
||||
if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || AI_DATA->aiPredictionInProgress))
|
||||
if (gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || gAiLogicData->aiPredictionInProgress))
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
}
|
||||
// If at -3 or worse, switch out regardless
|
||||
@ -1080,7 +1080,7 @@ bool32 ShouldSwitch(u32 battler)
|
||||
return FALSE;
|
||||
|
||||
// Sequence Switching AI never switches mid-battle
|
||||
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING)
|
||||
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING)
|
||||
return FALSE;
|
||||
|
||||
availableToSwitch = 0;
|
||||
@ -1132,7 +1132,7 @@ bool32 ShouldSwitch(u32 battler)
|
||||
|
||||
if (ShouldSwitchIfWonderGuard(battler))
|
||||
return TRUE;
|
||||
if ((AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE))
|
||||
if ((gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE))
|
||||
return FALSE;
|
||||
if (ShouldSwitchIfTrapperInParty(battler))
|
||||
return TRUE;
|
||||
@ -1160,7 +1160,7 @@ bool32 ShouldSwitch(u32 battler)
|
||||
// Removing switch capabilites under specific conditions
|
||||
// These Functions prevent the "FindMonWithFlagsAndSuperEffective" from getting out of hand.
|
||||
// We don't use FindMonWithFlagsAndSuperEffective with AI_FLAG_SMART_SWITCHING, so we can bail early.
|
||||
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)
|
||||
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)
|
||||
return FALSE;
|
||||
if (HasSuperEffectiveMoveAgainstOpponents(battler, FALSE))
|
||||
return FALSE;
|
||||
@ -1179,7 +1179,7 @@ bool32 ShouldSwitch(u32 battler)
|
||||
bool32 ShouldSwitchIfAllScoresBad(u32 battler)
|
||||
{
|
||||
u32 i, score, opposingBattler = GetOppositeBattler(battler);
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
@ -1229,7 +1229,7 @@ void ModifySwitchAfterMoveScoring(u32 battler)
|
||||
return;
|
||||
|
||||
// Sequence Switching AI never switches mid-battle
|
||||
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING)
|
||||
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING)
|
||||
return;
|
||||
|
||||
availableToSwitch = 0;
|
||||
@ -1274,9 +1274,9 @@ void ModifySwitchAfterMoveScoring(u32 battler)
|
||||
return;
|
||||
|
||||
if (ShouldSwitchIfAllScoresBad(battler))
|
||||
AI_DATA->shouldSwitch |= (1u << battler);
|
||||
gAiLogicData->shouldSwitch |= (1u << battler);
|
||||
else if (ShouldStayInToUseMove(battler))
|
||||
AI_DATA->shouldSwitch &= ~(1u << battler);
|
||||
gAiLogicData->shouldSwitch &= ~(1u << battler);
|
||||
}
|
||||
|
||||
bool32 IsSwitchinValid(u32 battler)
|
||||
@ -1287,14 +1287,14 @@ bool32 IsSwitchinValid(u32 battler)
|
||||
u32 partner = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerAtPosition(battler)));
|
||||
if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE) // Generic switch
|
||||
{
|
||||
if ((AI_DATA->shouldSwitch & (1u << partner)) && AI_DATA->monToSwitchInId[partner] == AI_DATA->mostSuitableMonId[battler])
|
||||
if ((gAiLogicData->shouldSwitch & (1u << partner)) && gAiLogicData->monToSwitchInId[partner] == gAiLogicData->mostSuitableMonId[battler])
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else // Override switch
|
||||
{
|
||||
if ((AI_DATA->shouldSwitch & (1u << partner)) && AI_DATA->monToSwitchInId[partner] == gBattleStruct->AI_monToSwitchIntoId[battler])
|
||||
if ((gAiLogicData->shouldSwitch & (1u << partner)) && gAiLogicData->monToSwitchInId[partner] == gBattleStruct->AI_monToSwitchIntoId[battler])
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@ -1314,12 +1314,12 @@ void AI_TrySwitchOrUseItem(u32 battler)
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
|
||||
{
|
||||
if (AI_DATA->shouldSwitch & (1u << battler) && IsSwitchinValid(battler))
|
||||
if (gAiLogicData->shouldSwitch & (1u << battler) && IsSwitchinValid(battler))
|
||||
{
|
||||
BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0);
|
||||
if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE)
|
||||
{
|
||||
s32 monToSwitchId = AI_DATA->mostSuitableMonId[battler];
|
||||
s32 monToSwitchId = gAiLogicData->mostSuitableMonId[battler];
|
||||
if (monToSwitchId == PARTY_SIZE)
|
||||
{
|
||||
if (!IsDoubleBattle())
|
||||
@ -1358,7 +1358,7 @@ void AI_TrySwitchOrUseItem(u32 battler)
|
||||
}
|
||||
|
||||
gBattleStruct->monToSwitchIntoId[battler] = gBattleStruct->AI_monToSwitchIntoId[battler];
|
||||
AI_DATA->monToSwitchInId[battler] = gBattleStruct->AI_monToSwitchIntoId[battler];
|
||||
gAiLogicData->monToSwitchInId[battler] = gBattleStruct->AI_monToSwitchIntoId[battler];
|
||||
return;
|
||||
}
|
||||
else if (ShouldUseItem(battler))
|
||||
@ -1481,11 +1481,11 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
|
||||
InitializeSwitchinCandidate(&party[i]);
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
aiMove = AI_DATA->switchinCandidate.battleMon.moves[j];
|
||||
aiMove = gAiLogicData->switchinCandidate.battleMon.moves[j];
|
||||
if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove))
|
||||
{
|
||||
aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j);
|
||||
dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, AI_ATTACKING);
|
||||
dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, AI_ATTACKING);
|
||||
if (bestDmg < dmg)
|
||||
{
|
||||
bestDmg = dmg;
|
||||
@ -1575,8 +1575,8 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon
|
||||
// Gets damage / healing from weather
|
||||
static s32 GetSwitchinWeatherImpact(void)
|
||||
{
|
||||
s32 weatherImpact = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability;
|
||||
enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item);
|
||||
s32 weatherImpact = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, ability = gAiLogicData->switchinCandidate.battleMon.ability;
|
||||
enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(gAiLogicData->switchinCandidate.battleMon.item);
|
||||
|
||||
if (HasWeatherEffect())
|
||||
{
|
||||
@ -1584,7 +1584,7 @@ static s32 GetSwitchinWeatherImpact(void)
|
||||
if (holdEffect != HOLD_EFFECT_SAFETY_GOGGLES && ability != ABILITY_MAGIC_GUARD && ability != ABILITY_OVERCOAT)
|
||||
{
|
||||
if ((gBattleWeather & B_WEATHER_HAIL)
|
||||
&& (AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_ICE || AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_ICE)
|
||||
&& (gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_ICE || gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_ICE)
|
||||
&& ability != ABILITY_SNOW_CLOAK && ability != ABILITY_ICE_BODY)
|
||||
{
|
||||
weatherImpact = maxHP / 16;
|
||||
@ -1592,9 +1592,9 @@ static s32 GetSwitchinWeatherImpact(void)
|
||||
weatherImpact = 1;
|
||||
}
|
||||
else if ((gBattleWeather & B_WEATHER_SANDSTORM)
|
||||
&& (AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_GROUND && AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_GROUND
|
||||
&& AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_ROCK && AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_ROCK
|
||||
&& AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_STEEL && AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_STEEL
|
||||
&& (gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_GROUND && gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_GROUND
|
||||
&& gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_ROCK && gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_ROCK
|
||||
&& gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_STEEL && gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_STEEL
|
||||
&& ability != ABILITY_SAND_VEIL && ability != ABILITY_SAND_RUSH && ability != ABILITY_SAND_FORCE))
|
||||
{
|
||||
weatherImpact = maxHP / 16;
|
||||
@ -1639,13 +1639,13 @@ static s32 GetSwitchinWeatherImpact(void)
|
||||
// Gets one turn of recurring healing
|
||||
static u32 GetSwitchinRecurringHealing(void)
|
||||
{
|
||||
u32 recurringHealing = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability;
|
||||
enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item);
|
||||
u32 recurringHealing = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, ability = gAiLogicData->switchinCandidate.battleMon.ability;
|
||||
enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(gAiLogicData->switchinCandidate.battleMon.item);
|
||||
|
||||
// Items
|
||||
if (ability != ABILITY_KLUTZ)
|
||||
{
|
||||
if (holdEffect == HOLD_EFFECT_BLACK_SLUDGE && (AI_DATA->switchinCandidate.battleMon.types[0] == TYPE_POISON || AI_DATA->switchinCandidate.battleMon.types[1] == TYPE_POISON))
|
||||
if (holdEffect == HOLD_EFFECT_BLACK_SLUDGE && (gAiLogicData->switchinCandidate.battleMon.types[0] == TYPE_POISON || gAiLogicData->switchinCandidate.battleMon.types[1] == TYPE_POISON))
|
||||
{
|
||||
recurringHealing = maxHP / 16;
|
||||
if (recurringHealing == 0)
|
||||
@ -1660,7 +1660,7 @@ static u32 GetSwitchinRecurringHealing(void)
|
||||
} // Intentionally omitting Shell Bell for its inconsistency
|
||||
|
||||
// Abilities
|
||||
if (ability == ABILITY_POISON_HEAL && (AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_POISON))
|
||||
if (ability == ABILITY_POISON_HEAL && (gAiLogicData->switchinCandidate.battleMon.status1 & STATUS1_POISON))
|
||||
{
|
||||
u32 healing = maxHP / 8;
|
||||
if (healing == 0)
|
||||
@ -1673,13 +1673,13 @@ static u32 GetSwitchinRecurringHealing(void)
|
||||
// Gets one turn of recurring damage
|
||||
static u32 GetSwitchinRecurringDamage(void)
|
||||
{
|
||||
u32 passiveDamage = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability;
|
||||
enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item);
|
||||
u32 passiveDamage = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, ability = gAiLogicData->switchinCandidate.battleMon.ability;
|
||||
enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(gAiLogicData->switchinCandidate.battleMon.item);
|
||||
|
||||
// Items
|
||||
if (ability != ABILITY_MAGIC_GUARD && ability != ABILITY_KLUTZ)
|
||||
{
|
||||
if (holdEffect == HOLD_EFFECT_BLACK_SLUDGE && AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_POISON && AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_POISON)
|
||||
if (holdEffect == HOLD_EFFECT_BLACK_SLUDGE && gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_POISON && gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_POISON)
|
||||
{
|
||||
passiveDamage = maxHP / 8;
|
||||
if (passiveDamage == 0)
|
||||
@ -1704,14 +1704,14 @@ static u32 GetSwitchinRecurringDamage(void)
|
||||
// Gets one turn of status damage
|
||||
static u32 GetSwitchinStatusDamage(u32 battler)
|
||||
{
|
||||
u8 defType1 = AI_DATA->switchinCandidate.battleMon.types[0], defType2 = AI_DATA->switchinCandidate.battleMon.types[1];
|
||||
u8 defType1 = gAiLogicData->switchinCandidate.battleMon.types[0], defType2 = gAiLogicData->switchinCandidate.battleMon.types[1];
|
||||
u8 tSpikesLayers = gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount;
|
||||
u16 heldItemEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item);
|
||||
u32 status = AI_DATA->switchinCandidate.battleMon.status1, ability = AI_DATA->switchinCandidate.battleMon.ability, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP;
|
||||
u16 heldItemEffect = ItemId_GetHoldEffect(gAiLogicData->switchinCandidate.battleMon.item);
|
||||
u32 status = gAiLogicData->switchinCandidate.battleMon.status1, ability = gAiLogicData->switchinCandidate.battleMon.ability, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP;
|
||||
u32 statusDamage = 0;
|
||||
|
||||
// Status condition damage
|
||||
if ((status != 0) && AI_DATA->switchinCandidate.battleMon.ability != ABILITY_MAGIC_GUARD)
|
||||
if ((status != 0) && gAiLogicData->switchinCandidate.battleMon.ability != ABILITY_MAGIC_GUARD)
|
||||
{
|
||||
if (status & STATUS1_BURN)
|
||||
{
|
||||
@ -1742,11 +1742,11 @@ static u32 GetSwitchinStatusDamage(u32 battler)
|
||||
else if ((status & STATUS1_TOXIC_POISON) && ability != ABILITY_POISON_HEAL)
|
||||
{
|
||||
if ((status & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_TURN(15)) // not 16 turns
|
||||
AI_DATA->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1);
|
||||
gAiLogicData->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1);
|
||||
statusDamage = maxHP / 16;
|
||||
if (statusDamage == 0)
|
||||
statusDamage = 1;
|
||||
statusDamage *= AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_COUNTER >> 8;
|
||||
statusDamage *= gAiLogicData->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_COUNTER >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1762,14 +1762,14 @@ static u32 GetSwitchinStatusDamage(u32 battler)
|
||||
{
|
||||
if (tSpikesLayers == 1)
|
||||
{
|
||||
AI_DATA->switchinCandidate.battleMon.status1 = STATUS1_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes
|
||||
AI_DATA->switchinCandidate.hypotheticalStatus = TRUE;
|
||||
gAiLogicData->switchinCandidate.battleMon.status1 = STATUS1_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes
|
||||
gAiLogicData->switchinCandidate.hypotheticalStatus = TRUE;
|
||||
}
|
||||
if (tSpikesLayers == 2)
|
||||
{
|
||||
AI_DATA->switchinCandidate.battleMon.status1 = STATUS1_TOXIC_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes
|
||||
AI_DATA->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1);
|
||||
AI_DATA->switchinCandidate.hypotheticalStatus = TRUE;
|
||||
gAiLogicData->switchinCandidate.battleMon.status1 = STATUS1_TOXIC_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes
|
||||
gAiLogicData->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1);
|
||||
gAiLogicData->switchinCandidate.hypotheticalStatus = TRUE;
|
||||
}
|
||||
}
|
||||
return statusDamage;
|
||||
@ -1778,16 +1778,16 @@ static u32 GetSwitchinStatusDamage(u32 battler)
|
||||
// Gets number of hits to KO factoring in hazards, healing held items, status, and weather
|
||||
static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler)
|
||||
{
|
||||
u32 startingHP = AI_DATA->switchinCandidate.battleMon.hp - GetSwitchinHazardsDamage(battler, &AI_DATA->switchinCandidate.battleMon);
|
||||
u32 startingHP = gAiLogicData->switchinCandidate.battleMon.hp - GetSwitchinHazardsDamage(battler, &gAiLogicData->switchinCandidate.battleMon);
|
||||
s32 weatherImpact = GetSwitchinWeatherImpact(); // Signed to handle both damage and healing in the same value
|
||||
u32 recurringDamage = GetSwitchinRecurringDamage();
|
||||
u32 recurringHealing = GetSwitchinRecurringHealing();
|
||||
u32 statusDamage = GetSwitchinStatusDamage(battler);
|
||||
u32 hitsToKO = 0, singleUseItemHeal = 0;
|
||||
u16 maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, item = AI_DATA->switchinCandidate.battleMon.item, heldItemEffect = ItemId_GetHoldEffect(item);
|
||||
u16 maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, item = gAiLogicData->switchinCandidate.battleMon.item, heldItemEffect = ItemId_GetHoldEffect(item);
|
||||
u8 weatherDuration = gWishFutureKnock.weatherDuration, holdEffectParam = ItemId_GetHoldEffectParam(item);
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
u32 opposingAbility = gBattleMons[opposingBattler].ability, ability = AI_DATA->switchinCandidate.battleMon.ability;
|
||||
u32 opposingAbility = gBattleMons[opposingBattler].ability, ability = gAiLogicData->switchinCandidate.battleMon.ability;
|
||||
bool32 usedSingleUseHealingItem = FALSE, opponentCanBreakMold = IsMoldBreakerTypeAbility(opposingBattler, opposingAbility);
|
||||
s32 currentHP = startingHP;
|
||||
|
||||
@ -1818,7 +1818,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler)
|
||||
currentHP = currentHP - weatherImpact;
|
||||
|
||||
// Check if we're at a single use healing item threshold
|
||||
if (AI_DATA->switchinCandidate.battleMon.ability != ABILITY_KLUTZ && usedSingleUseHealingItem == FALSE
|
||||
if (gAiLogicData->switchinCandidate.battleMon.ability != ABILITY_KLUTZ && usedSingleUseHealingItem == FALSE
|
||||
&& !(opposingAbility == ABILITY_UNNERVE && GetPocketByItemId(item) == POCKET_BERRIES))
|
||||
{
|
||||
switch (heldItemEffect)
|
||||
@ -1865,7 +1865,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler)
|
||||
currentHP = currentHP + recurringHealing - recurringDamage - statusDamage;
|
||||
|
||||
// Recalculate toxic damage if needed
|
||||
if (AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_POISON)
|
||||
if (gAiLogicData->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_POISON)
|
||||
statusDamage = GetSwitchinStatusDamage(battler);
|
||||
|
||||
// Reduce weather duration
|
||||
@ -1876,14 +1876,14 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler)
|
||||
}
|
||||
|
||||
// Disguise will always add an extra hit to KO
|
||||
if (opponentCanBreakMold && AI_DATA->switchinCandidate.battleMon.species == SPECIES_MIMIKYU_DISGUISED)
|
||||
if (opponentCanBreakMold && gAiLogicData->switchinCandidate.battleMon.species == SPECIES_MIMIKYU_DISGUISED)
|
||||
hitsToKO++;
|
||||
|
||||
// If mon had a hypothetical status from TSpikes, clear it
|
||||
if (AI_DATA->switchinCandidate.hypotheticalStatus == TRUE)
|
||||
if (gAiLogicData->switchinCandidate.hypotheticalStatus == TRUE)
|
||||
{
|
||||
AI_DATA->switchinCandidate.battleMon.status1 = 0;
|
||||
AI_DATA->switchinCandidate.hypotheticalStatus = FALSE;
|
||||
gAiLogicData->switchinCandidate.battleMon.status1 = 0;
|
||||
gAiLogicData->switchinCandidate.hypotheticalStatus = FALSE;
|
||||
}
|
||||
return hitsToKO;
|
||||
}
|
||||
@ -1956,7 +1956,7 @@ static bool32 CanAbilityTrapOpponent(u16 ability, u32 opponent)
|
||||
return FALSE;
|
||||
else if (ability == ABILITY_SHADOW_TAG)
|
||||
{
|
||||
if (B_SHADOW_TAG_ESCAPE >= GEN_4 && AI_DATA->abilities[opponent] == ABILITY_SHADOW_TAG) // Check if ability exists in species
|
||||
if (B_SHADOW_TAG_ESCAPE >= GEN_4 && gAiLogicData->abilities[opponent] == ABILITY_SHADOW_TAG) // Check if ability exists in species
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
@ -1978,9 +1978,9 @@ static inline bool32 IsFreeSwitch(enum SwitchType switchType, u32 battlerSwitchi
|
||||
{
|
||||
if (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) && movedSecond)
|
||||
return TRUE;
|
||||
if (AI_DATA->ejectButtonSwitch)
|
||||
if (gAiLogicData->ejectButtonSwitch)
|
||||
return TRUE;
|
||||
if (AI_DATA->ejectPackSwitch)
|
||||
if (gAiLogicData->ejectPackSwitch)
|
||||
{
|
||||
u32 opposingAbility = AI_GetBattlerAbility(opposingBattler);
|
||||
// If faster, not a free switch; likely lowered own stats
|
||||
@ -2050,12 +2050,12 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
InitializeSwitchinCandidate(&party[i]);
|
||||
|
||||
// While not really invalid per se, not really wise to switch into this mon
|
||||
if (AI_DATA->switchinCandidate.battleMon.ability == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler))
|
||||
if (gAiLogicData->switchinCandidate.battleMon.ability == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler))
|
||||
continue;
|
||||
|
||||
// Get max number of hits for player to KO AI mon and type matchup for defensive switching
|
||||
hitsToKOAI = GetSwitchinHitsToKO(GetMaxDamagePlayerCouldDealToSwitchin(battler, opposingBattler, AI_DATA->switchinCandidate.battleMon), battler);
|
||||
typeMatchup = GetSwitchinTypeMatchup(opposingBattler, AI_DATA->switchinCandidate.battleMon);
|
||||
hitsToKOAI = GetSwitchinHitsToKO(GetMaxDamagePlayerCouldDealToSwitchin(battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon), battler);
|
||||
typeMatchup = GetSwitchinTypeMatchup(opposingBattler, gAiLogicData->switchinCandidate.battleMon);
|
||||
|
||||
// Track max hits to KO and set defensive mon
|
||||
if(hitsToKOAI > maxHitsToKO)
|
||||
@ -2068,13 +2068,13 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
// Check through current mon's moves
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
aiMove = AI_DATA->switchinCandidate.battleMon.moves[j];
|
||||
aiMove = gAiLogicData->switchinCandidate.battleMon.moves[j];
|
||||
|
||||
if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove))
|
||||
damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, AI_ATTACKING);
|
||||
damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, AI_ATTACKING);
|
||||
|
||||
// Offensive switchin decisions are based on which whether switchin moves first and whether it can win a 1v1
|
||||
isSwitchinFirst = AI_WhoStrikesFirstPartyMon(battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, aiMove);
|
||||
isSwitchinFirst = AI_WhoStrikesFirstPartyMon(battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, aiMove);
|
||||
canSwitchinWin1v1 = CanSwitchinWin1v1(hitsToKOAI, GetNoOfHitsToKOBattlerDmg(damageDealt, opposingBattler), isSwitchinFirst, isFreeSwitch);
|
||||
|
||||
// Check for Baton Pass; hitsToKO requirements mean mon can boost and BP without dying whether it's slower or not
|
||||
@ -2149,8 +2149,8 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
}
|
||||
|
||||
// If mon can trap
|
||||
if ((CanAbilityTrapOpponent(AI_DATA->switchinCandidate.battleMon.ability, opposingBattler)
|
||||
|| (CanAbilityTrapOpponent(AI_GetBattlerAbility(opposingBattler), opposingBattler) && AI_DATA->switchinCandidate.battleMon.ability == ABILITY_TRACE))
|
||||
if ((CanAbilityTrapOpponent(gAiLogicData->switchinCandidate.battleMon.ability, opposingBattler)
|
||||
|| (CanAbilityTrapOpponent(AI_GetBattlerAbility(opposingBattler), opposingBattler) && gAiLogicData->switchinCandidate.battleMon.ability == ABILITY_TRACE))
|
||||
&& CountUsablePartyMons(opposingBattler) > 0
|
||||
&& canSwitchinWin1v1)
|
||||
trapperId = i;
|
||||
@ -2185,7 +2185,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
}
|
||||
// If ace mon is the last available Pokemon and U-Turn/Volt Switch or Eject Pack/Button was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount
|
||||
&& (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || AI_DATA->ejectButtonSwitch || AI_DATA->ejectPackSwitch))
|
||||
&& (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || gAiLogicData->ejectButtonSwitch || gAiLogicData->ejectPackSwitch))
|
||||
return aceMonId;
|
||||
|
||||
return PARTY_SIZE;
|
||||
@ -2247,14 +2247,14 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType)
|
||||
GetAIPartyIndexes(battler, &firstId, &lastId);
|
||||
party = GetBattlerParty(battler);
|
||||
|
||||
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING)
|
||||
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING)
|
||||
{
|
||||
bestMonId = GetNextMonInParty(party, firstId, lastId, battlerIn1, battlerIn2);
|
||||
return bestMonId;
|
||||
}
|
||||
|
||||
// Only use better mon selection if AI_FLAG_SMART_MON_CHOICES is set for the trainer.
|
||||
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic
|
||||
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic
|
||||
{
|
||||
bestMonId = GetBestMonIntegrated(party, firstId, lastId, battler, opposingBattler, battlerIn1, battlerIn2, switchType);
|
||||
return bestMonId;
|
||||
@ -2302,7 +2302,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType)
|
||||
|
||||
// If ace mon is the last available Pokemon and U-Turn/Volt Switch or Eject Pack/Button was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount
|
||||
&& (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || AI_DATA->ejectButtonSwitch || AI_DATA->ejectPackSwitch))
|
||||
&& (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || gAiLogicData->ejectButtonSwitch || gAiLogicData->ejectPackSwitch))
|
||||
return aceMonId;
|
||||
|
||||
return PARTY_SIZE;
|
||||
@ -2365,7 +2365,7 @@ static bool32 ShouldUseItem(u32 battler)
|
||||
const u8 *itemEffects;
|
||||
u8 battlerSide;
|
||||
|
||||
item = gBattleResources->battleHistory->trainerItems[i];
|
||||
item = gBattleHistory->trainerItems[i];
|
||||
if (item == ITEM_NONE)
|
||||
continue;
|
||||
itemEffects = ItemId_GetEffect(item);
|
||||
@ -2435,7 +2435,7 @@ static bool32 ShouldUseItem(u32 battler)
|
||||
gBattleStruct->itemPartyIndex[battler] = gBattlerPartyIndexes[battler];
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_USE_ITEM, 0);
|
||||
gBattleStruct->chosenItem[battler] = item;
|
||||
gBattleResources->battleHistory->trainerItems[i] = 0;
|
||||
gBattleHistory->trainerItems[i] = 0;
|
||||
return shouldUse;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -650,14 +650,14 @@ static void OpponentHandleChooseItem(u32 battler)
|
||||
|
||||
static inline bool32 IsAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 battler)
|
||||
{
|
||||
return AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON
|
||||
return gAiThinkingStruct->aiFlags[battler] & AI_FLAG_ACE_POKEMON
|
||||
&& (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1)
|
||||
&& CountAIAliveNonEggMonsExcept(PARTY_SIZE) != pokemonInBattle;
|
||||
}
|
||||
|
||||
static inline bool32 IsDoubleAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 battler)
|
||||
{
|
||||
return AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON
|
||||
return gAiThinkingStruct->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON
|
||||
&& (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1)
|
||||
&& (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 2)
|
||||
&& CountAIAliveNonEggMonsExcept(PARTY_SIZE) != pokemonInBattle
|
||||
|
||||
@ -972,7 +972,7 @@ static void PutMovesPointsText(struct BattleDebugMenu *data)
|
||||
AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 83 + count * 54, i * 15, 0, NULL);
|
||||
|
||||
ConvertIntToDecimalStringN(text,
|
||||
AI_GetDamage(data->aiBattlerId, battlerDef, i, AI_ATTACKING, AI_DATA),
|
||||
AI_GetDamage(data->aiBattlerId, battlerDef, i, AI_ATTACKING, gAiLogicData),
|
||||
STR_CONV_MODE_RIGHT_ALIGN, 3);
|
||||
AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 110 + count * 54, i * 15, 0, NULL);
|
||||
|
||||
@ -980,9 +980,9 @@ static void PutMovesPointsText(struct BattleDebugMenu *data)
|
||||
}
|
||||
}
|
||||
|
||||
if (AI_DATA->shouldSwitch & (1u << data->aiBattlerId))
|
||||
if (gAiLogicData->shouldSwitch & (1u << data->aiBattlerId))
|
||||
{
|
||||
u32 switchMon = GetMonData(&gEnemyParty[AI_DATA->mostSuitableMonId[data->aiBattlerId]], MON_DATA_SPECIES);
|
||||
u32 switchMon = GetMonData(&gEnemyParty[gAiLogicData->mostSuitableMonId[data->aiBattlerId]], MON_DATA_SPECIES);
|
||||
|
||||
AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, sText_IsSwitching, 74, 64, 0, NULL);
|
||||
AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, gSpeciesInfo[switchMon].speciesName, 74 + 68, 64, 0, NULL);
|
||||
@ -1128,9 +1128,9 @@ static void PutAiInfoText(struct BattleDebugMenu *data)
|
||||
{
|
||||
if (IsOnPlayerSide(i) && IsBattlerAlive(i))
|
||||
{
|
||||
u16 ability = AI_DATA->abilities[i];
|
||||
enum ItemHoldEffect holdEffect = AI_DATA->holdEffects[i];
|
||||
u16 item = AI_DATA->items[i];
|
||||
u16 ability = gAiLogicData->abilities[i];
|
||||
enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[i];
|
||||
u16 item = gAiLogicData->items[i];
|
||||
u8 x = (i == B_POSITION_PLAYER_LEFT) ? 83 + (i) * 75 : 83 + (i-1) * 75;
|
||||
AddTextPrinterParameterized(data->aiMovesWindowId, FONT_SMALL, gAbilitiesInfo[ability].name, x, 0, 0, NULL);
|
||||
AddTextPrinterParameterized(data->aiMovesWindowId, FONT_SMALL, ItemId_GetName(item), x, 15, 0, NULL);
|
||||
@ -1146,10 +1146,10 @@ static void PutAiPartyText(struct BattleDebugMenu *data)
|
||||
{
|
||||
u32 i, j, count;
|
||||
u8 *text = Alloc(0x50), *txtPtr;
|
||||
struct AiPartyMon *aiMons = AI_PARTY->mons[GetBattlerSide(data->aiBattlerId)];
|
||||
struct AiPartyMon *aiMons = gAiPartyData->mons[GetBattlerSide(data->aiBattlerId)];
|
||||
|
||||
FillWindowPixelBuffer(data->aiMovesWindowId, 0x11);
|
||||
count = AI_PARTY->count[GetBattlerSide(data->aiBattlerId)];
|
||||
count = gAiPartyData->count[GetBattlerSide(data->aiBattlerId)];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (aiMons[i].wasSentInBattle)
|
||||
@ -1275,8 +1275,8 @@ static void Task_ShowAiParty(u8 taskId)
|
||||
LoadMonIconPalettes();
|
||||
LoadPartyMenuAilmentGfx();
|
||||
data->aiBattlerId = data->battlerId;
|
||||
aiMons = AI_PARTY->mons[GetBattlerSide(data->aiBattlerId)];
|
||||
for (i = 0; i < AI_PARTY->count[GetBattlerSide(data->aiBattlerId)]; i++)
|
||||
aiMons = gAiPartyData->mons[GetBattlerSide(data->aiBattlerId)];
|
||||
for (i = 0; i < gAiPartyData->count[GetBattlerSide(data->aiBattlerId)]; i++)
|
||||
{
|
||||
u16 species = SPECIES_NONE; // Question mark
|
||||
if (aiMons[i].wasSentInBattle && aiMons[i].species)
|
||||
@ -2191,8 +2191,8 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data)
|
||||
data->modifyArrows.typeOfVal = VAL_BITFIELD_32;
|
||||
goto CASE_ITEM_STATUS;
|
||||
case LIST_ITEM_AI:
|
||||
data->modifyArrows.modifiedValPtr = &gBattleResources->ai->aiFlags[data->battlerId];
|
||||
data->modifyArrows.currValue = GetBitfieldValue(gBattleResources->ai->aiFlags[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount);
|
||||
data->modifyArrows.modifiedValPtr = &gAiThinkingStruct->aiFlags[data->battlerId];
|
||||
data->modifyArrows.currValue = GetBitfieldValue(gAiThinkingStruct->aiFlags[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount);
|
||||
data->modifyArrows.typeOfVal = VAL_BITFIELD_32;
|
||||
goto CASE_ITEM_STATUS;
|
||||
CASE_ITEM_STATUS:
|
||||
|
||||
@ -209,7 +209,14 @@ EWRAM_DATA u8 gSentPokesToOpponent[2] = {0};
|
||||
EWRAM_DATA struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT] = {0};
|
||||
EWRAM_DATA struct BattleScripting gBattleScripting = {0};
|
||||
EWRAM_DATA struct BattleStruct *gBattleStruct = NULL;
|
||||
|
||||
EWRAM_DATA struct AiThinkingStruct *gAiThinkingStruct = NULL;
|
||||
EWRAM_DATA struct AiLogicData *gAiLogicData = NULL;
|
||||
EWRAM_DATA struct AiPartyData *gAiPartyData = NULL;
|
||||
EWRAM_DATA struct BattleHistory *gBattleHistory = NULL;
|
||||
|
||||
EWRAM_DATA struct AiBattleData *gAiBattleData = NULL;
|
||||
|
||||
EWRAM_DATA u8 *gLinkBattleSendBuffer = NULL;
|
||||
EWRAM_DATA u8 *gLinkBattleRecvBuffer = NULL;
|
||||
EWRAM_DATA struct BattleResources *gBattleResources = NULL;
|
||||
@ -3230,8 +3237,8 @@ void SwitchInClearSetData(u32 battler)
|
||||
gSpecialStatuses[battler].enduredDamage = FALSE;
|
||||
|
||||
// Reset Eject Button / Eject Pack switch detection
|
||||
AI_DATA->ejectButtonSwitch = FALSE;
|
||||
AI_DATA->ejectPackSwitch = FALSE;
|
||||
gAiLogicData->ejectButtonSwitch = FALSE;
|
||||
gAiLogicData->ejectPackSwitch = FALSE;
|
||||
|
||||
// Reset G-Max Chi Strike boosts.
|
||||
gBattleStruct->bonusCritStages[battler] = 0;
|
||||
@ -3887,7 +3894,7 @@ static void TryDoEventsBeforeFirstTurn(void)
|
||||
|
||||
memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts));
|
||||
SetShellSideArmCategory();
|
||||
SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers
|
||||
SetAiLogicDataForTurn(gAiLogicData); // get assumed abilities, hold effects, etc of all battlers
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
||||
{
|
||||
@ -3990,7 +3997,7 @@ void BattleTurnPassed(void)
|
||||
BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG);
|
||||
AssignUsableGimmicks();
|
||||
SetShellSideArmCategory();
|
||||
SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers
|
||||
SetAiLogicDataForTurn(gAiLogicData); // get assumed abilities, hold effects, etc of all battlers
|
||||
gBattleMainFunc = HandleTurnActionSelectionState;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
||||
|
||||
@ -7096,7 +7096,7 @@ static void Cmd_moveend(void)
|
||||
gBattleStruct->battlerState[battler].usedEjectItem = TRUE;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_EjectButtonActivates;
|
||||
AI_DATA->ejectButtonSwitch = TRUE;
|
||||
gAiLogicData->ejectButtonSwitch = TRUE;
|
||||
break; // Only the fastest Eject Button activates
|
||||
}
|
||||
}
|
||||
@ -7150,7 +7150,7 @@ static void Cmd_moveend(void)
|
||||
gBattleStruct->battlerState[battler].usedEjectItem = TRUE;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_EjectPackActivates;
|
||||
AI_DATA->ejectPackSwitch = TRUE;
|
||||
gAiLogicData->ejectPackSwitch = TRUE;
|
||||
break; // Only the fastest Eject item activates
|
||||
}
|
||||
}
|
||||
@ -11591,13 +11591,13 @@ static void Cmd_various(void)
|
||||
case VARIOUS_SAVE_BATTLER_ITEM:
|
||||
{
|
||||
VARIOUS_ARGS();
|
||||
gBattleResources->battleHistory->heldItems[battler] = gBattleMons[battler].item;
|
||||
gBattleHistory->heldItems[battler] = gBattleMons[battler].item;
|
||||
break;
|
||||
}
|
||||
case VARIOUS_RESTORE_BATTLER_ITEM:
|
||||
{
|
||||
VARIOUS_ARGS();
|
||||
gBattleMons[battler].item = gBattleResources->battleHistory->heldItems[battler];
|
||||
gBattleMons[battler].item = gBattleHistory->heldItems[battler];
|
||||
break;
|
||||
}
|
||||
case VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM:
|
||||
@ -18656,7 +18656,7 @@ void BS_TryIntimidatEjectpack(void)
|
||||
{
|
||||
gProtectStructs[battler].statFell = FALSE;
|
||||
gProtectStructs[partnerBattler].statFell = FALSE;
|
||||
AI_DATA->ejectPackSwitch = TRUE;
|
||||
gAiLogicData->ejectPackSwitch = TRUE;
|
||||
gBattleScripting.battler = affectedBattler;
|
||||
gLastUsedItem = gBattleMons[affectedBattler].item;
|
||||
RecordItemEffectBattle(affectedBattler, HOLD_EFFECT_EJECT_PACK);
|
||||
|
||||
@ -2990,7 +2990,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a
|
||||
&& !IsBattlerAlly(battlerAtk, partnerDef))
|
||||
{
|
||||
if (option == ABILITY_CHECK_TRIGGER_AI)
|
||||
abilityDef = AI_DATA->abilities[partnerDef];
|
||||
abilityDef = gAiLogicData->abilities[partnerDef];
|
||||
else
|
||||
abilityDef = GetBattlerAbility(partnerDef);
|
||||
|
||||
@ -6076,7 +6076,7 @@ static enum ItemEffect TryEjectPack(u32 battler, enum ItemCaseId caseID)
|
||||
{
|
||||
gProtectStructs[battler].statFell = FALSE;
|
||||
gBattleScripting.battler = battler;
|
||||
AI_DATA->ejectPackSwitch = TRUE;
|
||||
gAiLogicData->ejectPackSwitch = TRUE;
|
||||
if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN)
|
||||
{
|
||||
BattleScriptExecute(BattleScript_EjectPackActivate_End2);
|
||||
@ -7811,7 +7811,7 @@ static bool32 IsBattlerGroundedInverseCheck(u32 battler, enum InverseBattleCheck
|
||||
return FALSE;
|
||||
if (holdEffect == HOLD_EFFECT_AIR_BALLOON)
|
||||
return FALSE;
|
||||
if ((AI_DATA->aiCalcInProgress ? AI_DATA->abilities[battler] : GetBattlerAbility(battler)) == ABILITY_LEVITATE)
|
||||
if ((gAiLogicData->aiCalcInProgress ? gAiLogicData->abilities[battler] : GetBattlerAbility(battler)) == ABILITY_LEVITATE)
|
||||
return FALSE;
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_FLYING) && (!(checkInverse == INVERSE_BATTLE) || !FlagGet(B_FLAG_INVERSE_BATTLE)))
|
||||
return FALSE;
|
||||
|
||||
@ -19,6 +19,10 @@ void AllocateBattleResources(void)
|
||||
|
||||
gBattleStruct = AllocZeroed(sizeof(*gBattleStruct));
|
||||
gAiBattleData = AllocZeroed(sizeof(*gAiBattleData));
|
||||
gAiThinkingStruct = AllocZeroed(sizeof(*gAiThinkingStruct));
|
||||
gAiLogicData = AllocZeroed(sizeof(*gAiLogicData));
|
||||
gAiPartyData = AllocZeroed(sizeof(*gAiPartyData));
|
||||
gBattleHistory = AllocZeroed(sizeof(*gBattleHistory));
|
||||
|
||||
#if B_FLAG_SKY_BATTLE
|
||||
gBattleStruct->isSkyBattle = FlagGet(B_FLAG_SKY_BATTLE);
|
||||
@ -29,10 +33,6 @@ void AllocateBattleResources(void)
|
||||
gBattleResources->battleScriptsStack = AllocZeroed(sizeof(*gBattleResources->battleScriptsStack));
|
||||
gBattleResources->battleCallbackStack = AllocZeroed(sizeof(*gBattleResources->battleCallbackStack));
|
||||
gBattleResources->beforeLvlUp = AllocZeroed(sizeof(*gBattleResources->beforeLvlUp));
|
||||
gBattleResources->ai = AllocZeroed(sizeof(*gBattleResources->ai));
|
||||
gBattleResources->aiData = AllocZeroed(sizeof(*gBattleResources->aiData));
|
||||
gBattleResources->aiParty = AllocZeroed(sizeof(*gBattleResources->aiParty));
|
||||
gBattleResources->battleHistory = AllocZeroed(sizeof(*gBattleResources->battleHistory));
|
||||
|
||||
gLinkBattleSendBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE);
|
||||
gLinkBattleRecvBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE);
|
||||
@ -57,15 +57,15 @@ void FreeBattleResources(void)
|
||||
{
|
||||
FREE_AND_SET_NULL(gBattleStruct);
|
||||
FREE_AND_SET_NULL(gAiBattleData);
|
||||
FREE_AND_SET_NULL(gAiThinkingStruct);
|
||||
FREE_AND_SET_NULL(gAiLogicData);
|
||||
FREE_AND_SET_NULL(gAiPartyData);
|
||||
FREE_AND_SET_NULL(gBattleHistory);
|
||||
|
||||
FREE_AND_SET_NULL(gBattleResources->secretBase);
|
||||
FREE_AND_SET_NULL(gBattleResources->battleScriptsStack);
|
||||
FREE_AND_SET_NULL(gBattleResources->battleCallbackStack);
|
||||
FREE_AND_SET_NULL(gBattleResources->beforeLvlUp);
|
||||
FREE_AND_SET_NULL(gBattleResources->ai);
|
||||
FREE_AND_SET_NULL(gBattleResources->aiData);
|
||||
FREE_AND_SET_NULL(gBattleResources->aiParty);
|
||||
FREE_AND_SET_NULL(gBattleResources->battleHistory);
|
||||
FREE_AND_SET_NULL(gBattleResources);
|
||||
|
||||
FREE_AND_SET_NULL(gLinkBattleSendBuffer);
|
||||
|
||||
@ -120,7 +120,7 @@ enum TimeMenuTimeOfDay
|
||||
DEBUG_TIME_MENU_ITEM_MORNING,
|
||||
DEBUG_TIME_MENU_ITEM_DAY,
|
||||
DEBUG_TIME_MENU_ITEM_EVENING,
|
||||
DEBUG_TIME_MENU_ITEM_NIGHT,
|
||||
DEBUG_TIME_MENU_ITEM_NIGHT,
|
||||
};
|
||||
|
||||
enum TimeMenuWeekdays
|
||||
@ -3776,7 +3776,7 @@ static void DebugAction_Give_DayCareEgg(u8 taskId)
|
||||
static void DebugAction_TimeMenu_ChangeTimeOfDay(u8 taskId)
|
||||
{
|
||||
u32 input = ListMenu_ProcessInput(gTasks[taskId].tMenuTaskId);
|
||||
|
||||
|
||||
DebugAction_DestroyExtraWindow(taskId);
|
||||
switch (input)
|
||||
{
|
||||
@ -3808,7 +3808,7 @@ static void DebugAction_TimeMenu_ChangeWeekdays(u8 taskId)
|
||||
{
|
||||
case DEBUG_TIME_MENU_ITEM_SUNDAY:
|
||||
daysToAdd = ((WEEKDAY_SUN - rtc->dayOfWeek) + WEEKDAY_COUNT) % WEEKDAY_COUNT;
|
||||
FakeRtc_AdvanceTimeBy(daysToAdd, 0, 0, 0);
|
||||
FakeRtc_AdvanceTimeBy(daysToAdd, 0, 0, 0);
|
||||
break;
|
||||
case DEBUG_TIME_MENU_ITEM_MONDAY:
|
||||
daysToAdd = ((WEEKDAY_MON - rtc->dayOfWeek) + WEEKDAY_COUNT) % WEEKDAY_COUNT;
|
||||
|
||||
@ -87,7 +87,7 @@ void RecordedBattle_Init(u8 mode)
|
||||
for (j = 0; j < BATTLER_RECORD_SIZE; j++)
|
||||
sBattleRecords[i][j] = 0xFF;
|
||||
sBattleFlags = gBattleTypeFlags;
|
||||
sAI_Scripts = gBattleResources->ai->aiFlags[B_POSITION_OPPONENT_LEFT];
|
||||
sAI_Scripts = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ AI_SINGLE_BATTLE_TEST("AI prefers Water Gun over Bubble if it knows that foe has
|
||||
} SCENE {
|
||||
MESSAGE("Shuckle's Defense fell!"); // Contrary activates
|
||||
} THEN {
|
||||
EXPECT(gBattleResources->aiData->abilities[B_POSITION_PLAYER_LEFT] == ABILITY_CONTRARY);
|
||||
EXPECT(gAiLogicData->abilities[B_POSITION_PLAYER_LEFT] == ABILITY_CONTRARY);
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,7 +749,7 @@ AI_DOUBLE_BATTLE_TEST("AI recognizes Volt Absorb received from Trace")
|
||||
} WHEN {
|
||||
TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_THUNDERSHOCK); NOT_EXPECT_MOVE(opponentLeft, MOVE_THUNDER_WAVE); NOT_EXPECT_MOVE(opponentRight, MOVE_THUNDER_WAVE); }
|
||||
} THEN {
|
||||
EXPECT(gBattleResources->aiData->abilities[B_POSITION_PLAYER_RIGHT] == ABILITY_VOLT_ABSORB);
|
||||
EXPECT(gAiLogicData->abilities[B_POSITION_PLAYER_RIGHT] == ABILITY_VOLT_ABSORB);
|
||||
}
|
||||
}
|
||||
|
||||
@ -942,15 +942,15 @@ SINGLE_BATTLE_TEST("AI correctly records used moves")
|
||||
TURN { MOVE(player, MOVE_TORCH_SONG); MOVE(opponent, MOVE_PSYCHIC); }
|
||||
TURN { MOVE(player, MOVE_GROWL); MOVE(opponent, MOVE_RAGE_FIST); }
|
||||
} THEN {
|
||||
EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_PLAYER_LEFT][0], MOVE_TACKLE);
|
||||
EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_PLAYER_LEFT][1], MOVE_GROWL);
|
||||
EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_PLAYER_LEFT][2], MOVE_FLOWER_TRICK);
|
||||
EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_PLAYER_LEFT][3], MOVE_TORCH_SONG);
|
||||
EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_PLAYER_LEFT][0], MOVE_TACKLE);
|
||||
EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_PLAYER_LEFT][1], MOVE_GROWL);
|
||||
EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_PLAYER_LEFT][2], MOVE_FLOWER_TRICK);
|
||||
EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_PLAYER_LEFT][3], MOVE_TORCH_SONG);
|
||||
|
||||
EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_OPPONENT_LEFT][0], MOVE_RAGE_FIST);
|
||||
EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_OPPONENT_LEFT][1], MOVE_PSYCHIC);
|
||||
EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_OPPONENT_LEFT][2], MOVE_SCRATCH);
|
||||
EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_OPPONENT_LEFT][3], MOVE_EARTHQUAKE);
|
||||
EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_OPPONENT_LEFT][0], MOVE_RAGE_FIST);
|
||||
EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_OPPONENT_LEFT][1], MOVE_PSYCHIC);
|
||||
EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_OPPONENT_LEFT][2], MOVE_SCRATCH);
|
||||
EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_OPPONENT_LEFT][3], MOVE_EARTHQUAKE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user