Skip to content

Commit

Permalink
Add AI_FLAG_OMNISCIENT (#2872)
Browse files Browse the repository at this point in the history
  • Loading branch information
AsparagusEduardo committed Apr 10, 2023
2 parents 16b89e9 + e3ca217 commit e4656f3
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 20 deletions.
4 changes: 2 additions & 2 deletions include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ struct AiPartyMon

struct AIPartyData // Opposing battlers - party mons.
{
struct AiPartyMon mons[2][PARTY_SIZE]; // 2 parties(player, opponent). Used to save information on opposing party.
u8 count[2];
struct AiPartyMon mons[NUM_BATTLE_SIDES][PARTY_SIZE]; // 2 parties(player, opponent). Used to save information on opposing party.
u8 count[NUM_BATTLE_SIDES];
};

struct AiLogicData
Expand Down
3 changes: 2 additions & 1 deletion include/battle_ai_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

bool32 AI_RandLessThan(u8 val);
void RecordLastUsedMoveByTarget(void);
bool32 IsBattlerAIControlled(u32 battlerId);
bool32 BattlerHasAi(u32 battlerId);
bool32 IsAiBattlerAware(u32 battlerId);
void ClearBattlerMoveHistory(u8 battlerId);
void RecordLastUsedMoveBy(u32 battlerId, u32 move);
void RecordKnownMove(u8 battlerId, u32 move);
Expand Down
1 change: 1 addition & 0 deletions include/constants/battle_ai.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#define AI_FLAG_SCREENER (1 << 14) // AI prefers screening effects like reflect, mist, etc. TODO unfinished
#define AI_FLAG_SMART_SWITCHING (1 << 15) // AI includes a lot more switching checks
#define AI_FLAG_ACE_POKEMON (1 << 16) // AI has an Ace Pokemon. The last Pokemon in the party will not be used until it's the last one remaining.
#define AI_FLAG_OMNISCIENT (1 << 17) // AI has full knowledge of player moves, abilities, hold items

// 'other' ai logic flags
#define AI_FLAG_ROAMING (1 << 29)
Expand Down
15 changes: 14 additions & 1 deletion src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ static void CopyBattlerDataToAIParty(u32 bPosition, u32 side)
void Ai_InitPartyStruct(void)
{
u32 i;
bool32 isOmniscient = (AI_THINKING_STRUCT->aiFlags & AI_FLAG_OMNISCIENT);
struct Pokemon *mon;

AI_PARTY->count[B_SIDE_PLAYER] = gPlayerPartyCount;
AI_PARTY->count[B_SIDE_OPPONENT] = gEnemyPartyCount;
Expand All @@ -278,6 +280,17 @@ void Ai_InitPartyStruct(void)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0)
AI_PARTY->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);
for (j = 0; j < MAX_MON_MOVES; j++)
AI_PARTY->mons[B_SIDE_PLAYER][i].moves[j] = GetMonData(mon, MON_DATA_MOVE1 + j);
}
}
}

Expand Down Expand Up @@ -354,7 +367,7 @@ void GetAiLogicData(void)
for (battlerAtk = 0; battlerAtk < gBattlersCount; battlerAtk++)
{
if (!IsBattlerAlive(battlerAtk)
|| !IsBattlerAIControlled(battlerAtk)) {
|| !IsAiBattlerAware(battlerAtk)) {
continue;
}

Expand Down
30 changes: 19 additions & 11 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ void RecordLastUsedMoveByTarget(void)
RecordKnownMove(gBattlerTarget, gLastMoves[gBattlerTarget]);
}

bool32 IsBattlerAIControlled(u32 battlerId)
bool32 BattlerHasAi(u32 battlerId)
{
switch (GetBattlerPosition(battlerId))
{
Expand All @@ -473,6 +473,14 @@ bool32 IsBattlerAIControlled(u32 battlerId)
}
}

bool32 IsAiBattlerAware(u32 battlerId)
{
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_OMNISCIENT)
return TRUE;

return BattlerHasAi(battlerId);
}

void ClearBattlerMoveHistory(u8 battlerId)
{
memset(BATTLE_HISTORY->usedMoves[battlerId], 0, sizeof(BATTLE_HISTORY->usedMoves[battlerId]));
Expand Down Expand Up @@ -529,7 +537,7 @@ void ClearBattlerItemEffectHistory(u8 battlerId)

void SaveBattlerData(u8 battlerId)
{
if (!IsBattlerAIControlled(battlerId))
if (!BattlerHasAi(battlerId))
{
u32 i;

Expand Down Expand Up @@ -580,7 +588,7 @@ static bool32 ShouldFailForIllusion(u16 illusionSpecies, u32 battlerId)

void SetBattlerData(u8 battlerId)
{
if (!IsBattlerAIControlled(battlerId))
if (!BattlerHasAi(battlerId))
{
u32 i, species, illusionSpecies;

Expand Down Expand Up @@ -623,7 +631,7 @@ void SetBattlerData(u8 battlerId)

void RestoreBattlerData(u8 battlerId)
{
if (!IsBattlerAIControlled(battlerId))
if (!BattlerHasAi(battlerId))
{
u32 i;

Expand Down Expand Up @@ -1223,15 +1231,15 @@ s32 AI_GetAbility(u32 battlerId)
return gBattleStruct->overwrittenAbilities[battlerId];

// The AI knows its own ability.
if (IsBattlerAIControlled(battlerId))
if (IsAiBattlerAware(battlerId))
return knownAbility;

// Check neutralizing gas, gastro acid
if (knownAbility == ABILITY_NONE)
return knownAbility;

if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE)
return BATTLE_HISTORY->abilities[battlerId];
if (AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability != ABILITY_NONE)
return AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability;

// Abilities that prevent fleeing - treat as always known
if (knownAbility == ABILITY_SHADOW_TAG || knownAbility == ABILITY_MAGNET_PULL || knownAbility == ABILITY_ARENA_TRAP)
Expand All @@ -1256,8 +1264,8 @@ u16 AI_GetHoldEffect(u32 battlerId)
{
u32 holdEffect;

if (!IsBattlerAIControlled(battlerId))
holdEffect = BATTLE_HISTORY->itemEffects[battlerId];
if (!IsAiBattlerAware(battlerId))
holdEffect = AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect;
else
holdEffect = GetBattlerHoldEffect(battlerId, FALSE);

Expand Down Expand Up @@ -1881,7 +1889,7 @@ bool32 CanIndexMoveFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHit

u16 *GetMovesArray(u32 battler)
{
if (IsBattlerAIControlled(battler) || IsBattlerAIControlled(BATTLE_PARTNER(battler)))
if (IsAiBattlerAware(battler) || IsAiBattlerAware(BATTLE_PARTNER(battler)))
return gBattleMons[battler].moves;
else
return gBattleResources->battleHistory->usedMoves[battler];
Expand Down Expand Up @@ -3136,7 +3144,7 @@ u16 GetAllyChosenMove(u8 battlerId)
{
u8 partnerBattler = BATTLE_PARTNER(battlerId);

if (!IsBattlerAlive(partnerBattler) || !IsBattlerAIControlled(partnerBattler))
if (!IsBattlerAlive(partnerBattler) || !IsAiBattlerAware(partnerBattler))
return MOVE_NONE;
else if (partnerBattler > battlerId) // Battler with the lower id chooses the move first.
return gLastMoves[partnerBattler];
Expand Down
4 changes: 2 additions & 2 deletions src/battle_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ static void Task_ShowAiPoints(u8 taskId)

// Swap battler if it's player mon
data->aiBattlerId = data->battlerId;
while (!IsBattlerAIControlled(data->aiBattlerId))
while (!BattlerHasAi(data->aiBattlerId))
{
if (++data->aiBattlerId >= gBattlersCount)
data->aiBattlerId = 0;
Expand Down Expand Up @@ -931,7 +931,7 @@ static void Task_ShowAiKnowledge(u8 taskId)

// Swap battler if it's player mon
data->aiBattlerId = data->battlerId;
while (!IsBattlerAIControlled(data->aiBattlerId))
while (!BattlerHasAi(data->aiBattlerId))
{
if (++data->aiBattlerId >= gBattlersCount)
data->aiBattlerId = 0;
Expand Down
5 changes: 3 additions & 2 deletions src/battle_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3882,7 +3882,7 @@ static void TryDoEventsBeforeFirstTurn(void)
gChosenActionByBattler[i] = B_ACTION_NONE;
gChosenMoveByBattler[i] = MOVE_NONE;
// Record party slots of player's mons that appeared in battle
if (!IsBattlerAIControlled(i))
if (!BattlerHasAi(i))
gBattleStruct->appearedInBattle |= gBitTable[gBattlerPartyIndexes[i]];
}
TurnValuesCleanUp(FALSE);
Expand Down Expand Up @@ -4119,7 +4119,8 @@ static void HandleTurnActionSelectionState(void)

// Do AI score computations here so we can use them in AI_TrySwitchOrUseItem
if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart())
&& (IsBattlerAIControlled(gActiveBattler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE))) {
&& (BattlerHasAi(gActiveBattler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE)))
{
gBattleStruct->aiMoveOrAction[gActiveBattler] = ComputeBattleAiScores(gActiveBattler);
}
break;
Expand Down
2 changes: 1 addition & 1 deletion src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -7037,7 +7037,7 @@ static void Cmd_switchineffects(void)
gHitMarker &= ~HITMARKER_FAINTED(gActiveBattler);
gSpecialStatuses[gActiveBattler].faintedHasReplacement = FALSE;

if (!IsBattlerAIControlled(gActiveBattler))
if (!BattlerHasAi(gActiveBattler))
gBattleStruct->appearedInBattle |= gBitTable[gBattlerPartyIndexes[gActiveBattler]];

// Neutralizing Gas announces itself before hazards
Expand Down

0 comments on commit e4656f3

Please sign in to comment.