From e1d8ef819066959425f875cc4b44dfbd72a61ee3 Mon Sep 17 00:00:00 2001 From: ghoulslash <41651341+ghoulslash@users.noreply.github.com> Date: Tue, 9 Jul 2024 07:50:48 -0400 Subject: [PATCH] Dynamic AI Functions (#4908) * dynamic ai func * add AI_TagBattlePreferFoe as an example * Update src/battle_ai_main.c * Update src/battle_ai_main.c --------- Co-authored-by: ghoulslash Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- asm/macros/event.inc | 5 ++++ include/battle_ai_main.h | 4 +++ include/constants/battle_ai.h | 1 + src/battle_ai_main.c | 52 ++++++++++++++++++++++++++++++++++- src/battle_main.c | 2 ++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/asm/macros/event.inc b/asm/macros/event.inc index bab06a0da1..a98887383c 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -2094,6 +2094,11 @@ setvar VAR_0x8006, \item special CreateEnemyEventMon .endm + + .macro setdynamicaifunc func:req + callnative ScriptSetDynamicAiFunc + .4byte \func + .endm @ Set up a totem boost for the next battle. @ 'battler' is the position of the mon you want to gain a boost. see B_POSITION_xx in include/constants/battle.h. diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index 60028eb8cd..770ec89f1c 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -1,6 +1,9 @@ #ifndef GUARD_BATTLE_AI_MAIN_H #define GUARD_BATTLE_AI_MAIN_H + +typedef s32 (*AiScoreFunc)(u32, u32, u32, s32); + #define UNKNOWN_NO_OF_HITS UINT32_MAX // return vals for BattleAI_ChooseMoveOrAction @@ -101,6 +104,7 @@ void Ai_InitPartyStruct(void); void Ai_UpdateSwitchInData(u32 battler); void Ai_UpdateFaintData(u32 battler); void SetAiLogicDataForTurn(struct AiLogicData *aiData); +void ResetDynamicAiFunc(void); extern u8 sBattler_AI; diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 79f8f04d6c..38d058a8cb 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -51,6 +51,7 @@ #define AI_FLAG_COUNT 20 // 'other' ai logic flags +#define AI_FLAG_DYNAMIC_FUNC (1 << 28) // Create custom AI functions for specific battles via "setdynamicaifunc" cmd #define AI_FLAG_ROAMING (1 << 29) #define AI_FLAG_SAFARI (1 << 30) #define AI_FLAG_FIRST_BATTLE (1 << 31) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index a21e13b8fc..3d03ba6f93 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -18,6 +18,7 @@ #include "random.h" #include "recorded_battle.h" #include "util.h" +#include "script.h" #include "constants/abilities.h" #include "constants/battle_ai.h" #include "constants/battle_move_effects.h" @@ -39,6 +40,7 @@ static bool32 IsPinchBerryItemEffect(u32 holdEffect); // ewram EWRAM_DATA const u8 *gAIScriptPtr = NULL; // Still used in contests EWRAM_DATA u8 sBattler_AI = 0; +EWRAM_DATA AiScoreFunc sDynamicAiFunc = NULL; // const rom data static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); @@ -54,6 +56,7 @@ static s32 AI_Safari(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_DynamicFunc(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) = @@ -86,7 +89,7 @@ static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) = [25] = NULL, // Unused [26] = NULL, // Unused [27] = NULL, // Unused - [28] = NULL, // Unused + [28] = AI_DynamicFunc, // AI_FLAG_DYNAMIC_FUNC [29] = AI_Roaming, // AI_FLAG_ROAMING [30] = AI_Safari, // AI_FLAG_SAFARI [31] = AI_FirstBattle, // AI_FLAG_FIRST_BATTLE @@ -179,6 +182,9 @@ static u32 GetAiFlags(u16 trainerId) // Automatically includes AI_FLAG_SMART_MON_CHOICES to improve smart switching if (flags & AI_FLAG_SMART_SWITCHING) flags |= AI_FLAG_SMART_MON_CHOICES; + + if (sDynamicAiFunc != NULL) + flags |= AI_FLAG_DYNAMIC_FUNC; return flags; } @@ -5335,3 +5341,47 @@ static s32 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) return score; } + + +// Dynamic AI Functions +// For specific battle scenarios + +// Example - prefer attacking opposite foe in a tag battle +s32 AI_TagBattlePreferFoe(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + if (!(gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)) + { + /* not a partner battle */ + return score; + } + else if (!IsBattlerAlive(BATTLE_OPPOSITE(battlerAtk)) || !IsBattlerAlive(BATTLE_PARTNER(BATTLE_OPPOSITE(battlerAtk)))) + { + /* partner is defeated so attack normally */ + return score; + } + else if (battlerDef == BATTLE_OPPOSITE(battlerAtk)) + { + /* attacking along the diagonal */ + ADJUST_SCORE(-20); + } + + return score; +} + +static s32 AI_DynamicFunc(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + if (sDynamicAiFunc != NULL) + score = sDynamicAiFunc(battlerAtk, battlerDef, move, score); + return score; +} + +void ScriptSetDynamicAiFunc(struct ScriptContext *ctx) +{ + AiScoreFunc func = (AiScoreFunc)ScriptReadWord(ctx); + sDynamicAiFunc = func; +} + +void ResetDynamicAiFunc(void) +{ + sDynamicAiFunc = NULL; +} diff --git a/src/battle_main.c b/src/battle_main.c index aeea09cd78..625f2dcd08 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -1766,6 +1766,7 @@ static void FreeRestoreBattleData(void) FreeMonSpritesGfx(); FreeBattleSpritesData(); FreeBattleResources(); + ResetDynamicAiFunc(); } void CB2_QuitRecordedBattle(void) @@ -5530,6 +5531,7 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) if (gBattleStruct != NULL && !(gBattleTypeFlags & BATTLE_TYPE_LINK)) { ZeroEnemyPartyMons(); + ResetDynamicAiFunc(); FreeMonSpritesGfx(); FreeBattleResources(); FreeBattleSpritesData();