From 00d695ac2b313c5a887d20aad4618f350725713c Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Tue, 28 Mar 2023 10:38:48 -0400 Subject: [PATCH 1/4] add AI_FLAG_OMNISCIENT --- include/battle.h | 4 ++-- include/battle_ai_util.h | 1 + include/constants/battle_ai.h | 1 + src/battle_ai_main.c | 13 +++++++++++++ src/battle_ai_util.c | 19 ++++++++++++++----- src/battle_debug.c | 4 ++-- src/battle_main.c | 4 ++-- 7 files changed, 35 insertions(+), 11 deletions(-) diff --git a/include/battle.h b/include/battle.h index 491273b80b..19f9df13d8 100644 --- a/include/battle.h +++ b/include/battle.h @@ -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 diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 11eba7b661..95f6619c5e 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -9,6 +9,7 @@ bool32 AI_RandLessThan(u8 val); void RecordLastUsedMoveByTarget(void); +bool32 BattlerHasAi(u32 battlerId); bool32 IsBattlerAIControlled(u32 battlerId); void ClearBattlerMoveHistory(u8 battlerId); void RecordLastUsedMoveBy(u32 battlerId, u32 move); diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 1cfb9cd4dc..1316054cd1 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -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) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 19eedb41cc..6e308003ad 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -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; @@ -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); + } } } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index a9e3ed3e0b..93586626e2 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -457,7 +457,7 @@ void RecordLastUsedMoveByTarget(void) RecordKnownMove(gBattlerTarget, gLastMoves[gBattlerTarget]); } -bool32 IsBattlerAIControlled(u32 battlerId) +bool32 BattlerHasAi(u32 battlerId) { switch (GetBattlerPosition(battlerId)) { @@ -473,6 +473,14 @@ bool32 IsBattlerAIControlled(u32 battlerId) } } +bool32 IsBattlerAIControlled(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])); @@ -1230,8 +1238,9 @@ s32 AI_GetAbility(u32 battlerId) 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) @@ -1257,10 +1266,10 @@ u16 AI_GetHoldEffect(u32 battlerId) u32 holdEffect; if (!IsBattlerAIControlled(battlerId)) - holdEffect = BATTLE_HISTORY->itemEffects[battlerId]; + holdEffect = AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect; else holdEffect = GetBattlerHoldEffect(battlerId, FALSE); - + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return holdEffect; diff --git a/src/battle_debug.c b/src/battle_debug.c index 027be03a45..1d690caaa0 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -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; @@ -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; diff --git a/src/battle_main.c b/src/battle_main.c index efbf1b8195..8e0dc6d878 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3859,7 +3859,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); @@ -4096,7 +4096,7 @@ 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; From 10ef3e83483c08cc5f62a1f7f0469aafdfa4f7b8 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Tue, 28 Mar 2023 10:58:44 -0400 Subject: [PATCH 2/4] style fixes --- src/battle_ai_util.c | 5 ++--- src/battle_main.c | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 93586626e2..51f4ef0467 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1238,9 +1238,8 @@ s32 AI_GetAbility(u32 battlerId) if (knownAbility == ABILITY_NONE) return knownAbility; - if (AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability != ABILITY_NONE) { + 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) @@ -1269,7 +1268,7 @@ u16 AI_GetHoldEffect(u32 battlerId) holdEffect = AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect; else holdEffect = GetBattlerHoldEffect(battlerId, FALSE); - + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return holdEffect; diff --git a/src/battle_main.c b/src/battle_main.c index 8e0dc6d878..8175528525 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4096,7 +4096,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()) - && (BattlerHasAi(gActiveBattler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE))) { + && (BattlerHasAi(gActiveBattler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE))) + { gBattleStruct->aiMoveOrAction[gActiveBattler] = ComputeBattleAiScores(gActiveBattler); } break; From e49bb21ee48e7e4dc6d1f14420622ddf50488a5e Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 10 Apr 2023 09:48:44 -0400 Subject: [PATCH 3/4] some IsBattlerAIControlled replacements w BattlerHasAi --- src/battle_ai_util.c | 6 +++--- src/battle_script_commands.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 51f4ef0467..3160dfa3f5 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -537,7 +537,7 @@ void ClearBattlerItemEffectHistory(u8 battlerId) void SaveBattlerData(u8 battlerId) { - if (!IsBattlerAIControlled(battlerId)) + if (!BattlerHasAi(battlerId)) { u32 i; @@ -588,7 +588,7 @@ static bool32 ShouldFailForIllusion(u16 illusionSpecies, u32 battlerId) void SetBattlerData(u8 battlerId) { - if (!IsBattlerAIControlled(battlerId)) + if (!BattlerHasAi(battlerId)) { u32 i, species, illusionSpecies; @@ -631,7 +631,7 @@ void SetBattlerData(u8 battlerId) void RestoreBattlerData(u8 battlerId) { - if (!IsBattlerAIControlled(battlerId)) + if (!BattlerHasAi(battlerId)) { u32 i; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 28bf60c39b..22c20c698b 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7036,7 +7036,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 From e3ca217d6412b4eccd325006904ca88a2f3a631c Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 10 Apr 2023 11:36:17 -0400 Subject: [PATCH 4/4] rename IsBattlerAIControlled --- include/battle_ai_util.h | 2 +- src/battle_ai_main.c | 2 +- src/battle_ai_util.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 68c0dbd993..d1319f0ca7 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -10,7 +10,7 @@ bool32 AI_RandLessThan(u8 val); void RecordLastUsedMoveByTarget(void); bool32 BattlerHasAi(u32 battlerId); -bool32 IsBattlerAIControlled(u32 battlerId); +bool32 IsAiBattlerAware(u32 battlerId); void ClearBattlerMoveHistory(u8 battlerId); void RecordLastUsedMoveBy(u32 battlerId, u32 move); void RecordKnownMove(u8 battlerId, u32 move); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 95e85ab894..2fb9c2640d 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -367,7 +367,7 @@ void GetAiLogicData(void) for (battlerAtk = 0; battlerAtk < gBattlersCount; battlerAtk++) { if (!IsBattlerAlive(battlerAtk) - || !IsBattlerAIControlled(battlerAtk)) { + || !IsAiBattlerAware(battlerAtk)) { continue; } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 22c7bb633c..05e7aec58f 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -473,7 +473,7 @@ bool32 BattlerHasAi(u32 battlerId) } } -bool32 IsBattlerAIControlled(u32 battlerId) +bool32 IsAiBattlerAware(u32 battlerId) { if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_OMNISCIENT) return TRUE; @@ -1231,7 +1231,7 @@ 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 @@ -1264,7 +1264,7 @@ u16 AI_GetHoldEffect(u32 battlerId) { u32 holdEffect; - if (!IsBattlerAIControlled(battlerId)) + if (!IsAiBattlerAware(battlerId)) holdEffect = AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect; else holdEffect = GetBattlerHoldEffect(battlerId, FALSE); @@ -1889,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]; @@ -3144,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];