From aad3a800c3adf9c429f489d3c6db90972bfdaba3 Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 10 Dec 2020 22:10:21 -0700 Subject: [PATCH] c functions for ai roamers/safari/first battle --- data/battle_ai_scripts.s | 64 +--------------------------- include/battle_ai_util.h | 8 ++++ ld_script.txt | 1 + src/battle_ai_script_commands.c | 75 ++++++++++++++++++++++----------- src/battle_ai_util.c | 47 +++++++++++++++++++++ 5 files changed, 108 insertions(+), 87 deletions(-) create mode 100644 include/battle_ai_util.h create mode 100644 src/battle_ai_util.c diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index 17238670d0..9e504dd55e 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -21,29 +21,7 @@ gBattleAI_ScriptsTable:: @ 82DBEF8 .4byte AI_PreferBatonPass @ AI_SCRIPT_PREFER_BATON_PASS .4byte AI_DoubleBattle @ AI_SCRIPT_DOUBLE_BATTLE .4byte AI_HPAware @ AI_SCRIPT_HP_AWARE - .4byte AI_Unknown @ AI_SCRIPT_UNKNOWN - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Ret - .4byte AI_Roaming @ AI_SCRIPT_ROAMING - .4byte AI_Safari @ AI_SCRIPT_SAFARI - .4byte AI_FirstBattle @ AI_SCRIPT_FIRST_BATTLE + AI_CheckBadMove: if_target_is_ally AI_Ret @@ -4140,47 +4118,7 @@ AI_HPAware_DiscouragedEffectsWhenTargetLowHP: @ 82DE2B1 .byte EFFECT_DRAGON_DANCE .byte -1 -AI_Unknown: - if_target_is_ally AI_TryOnAlly - if_not_effect EFFECT_SUNNY_DAY, AI_Unknown_End - if_equal 0, AI_Unknown_End - is_first_turn_for AI_USER - if_equal 0, AI_Unknown_End - score +5 -AI_Unknown_End: @ 82DE308 - end - -AI_Roaming: - if_status2 AI_USER, STATUS2_WRAPPED, AI_Roaming_End - if_status2 AI_USER, STATUS2_ESCAPE_PREVENTION, AI_Roaming_End - get_ability AI_TARGET - if_equal ABILITY_SHADOW_TAG, AI_Roaming_End - get_ability AI_USER - if_equal ABILITY_LEVITATE, AI_Roaming_Flee - get_ability AI_TARGET - if_equal ABILITY_ARENA_TRAP, AI_Roaming_End - -AI_Roaming_Flee: @ 82DE335 - flee - -AI_Roaming_End: @ 82DE336 - end - -AI_Safari: - if_random_safari_flee AI_Safari_Flee - watch - -AI_Safari_Flee: - flee - -AI_FirstBattle: - if_hp_equal AI_TARGET, 20, AI_FirstBattle_Flee - if_hp_less_than AI_TARGET, 20, AI_FirstBattle_Flee - end - -AI_FirstBattle_Flee: - flee AI_Ret: end diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h new file mode 100644 index 0000000000..2772c66216 --- /dev/null +++ b/include/battle_ai_util.h @@ -0,0 +1,8 @@ +#ifndef GUARD_BATTLE_AI_UTIL_H +#define GUARD_BATTLE_AI_UTIL_H + +u32 GetHealthPercentage(u8 battler); +bool32 IsBattlerTrapped(u8 battler, bool8 switching); + + +#endif //GUARD_BATTLE_AI_UTIL_H \ No newline at end of file diff --git a/ld_script.txt b/ld_script.txt index 091b6e693c..2bf411e627 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -214,6 +214,7 @@ SECTIONS { src/slot_machine.o(.text); src/contest_painting.o(.text); src/battle_ai_script_commands.o(.text); + src/battle_ai_util.o(.text); src/trader.o(.text); src/starter_choose.o(.text); src/wallclock.o(.text); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 22b1df3d56..695844bb28 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -2,6 +2,7 @@ #include "malloc.h" #include "battle.h" #include "battle_anim.h" +#include "battle_ai_util.h" #include "battle_ai_script_commands.h" #include "battle_factory.h" #include "battle_setup.h" @@ -187,18 +188,18 @@ EWRAM_DATA static u8 sBattler_AI = 0; // const rom data typedef void (*BattleAICmdFunc)(void); -static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); -static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability); +static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); +static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalScore); static u8 (*const sBattleAiFuncTable[])(u8, u8, u16, u8) = { @@ -2933,53 +2934,79 @@ static void Cmd_if_has_move_with_accuracy_lt(void) // AI Functions -static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { } -static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static void AI_Flee(void) { + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); } -static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static void AI_Watch(void) { + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); } -static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 originalMove, u8 originalViability) +static u8 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) { + if (IsBattlerTrapped(battlerAtk, FALSE)) + return originalScore; + AI_Flee(); + return originalScore; +} + +static u8 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +{ + u8 safariFleeRate = gBattleStruct->safariEscapeFactor * 5; // Safari flee rate, from 0-20. + + if ((Random() % 100) < safariFleeRate) + AI_Flee(); + else + AI_Watch(); + + return originalScore; +} + +static u8 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, u8 originalScore) +{ + if (GetHealthPercentage(battlerDef) <= 20) + AI_Flee(); + + return originalScore; } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c new file mode 100644 index 0000000000..8b9778668c --- /dev/null +++ b/src/battle_ai_util.c @@ -0,0 +1,47 @@ +#include "global.h" +#include "malloc.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_ai_util.h" +#include "battle_ai_script_commands.h" +#include "battle_factory.h" +#include "battle_setup.h" +#include "data.h" +#include "item.h" +#include "pokemon.h" +#include "random.h" +#include "recorded_battle.h" +#include "util.h" +#include "constants/abilities.h" +#include "constants/battle_ai.h" +#include "constants/battle_move_effects.h" +#include "constants/hold_effects.h" +#include "constants/moves.h" + +// Functions +u32 GetHealthPercentage(u8 battlerId) +{ + return (u32)(100 * gBattleMons[battlerId].hp / gBattleMons[battlerId].maxHP); +} + +bool32 IsBattlerTrapped(u8 battler, bool8 switching) +{ + u8 holdEffect = GetBattlerHoldEffect(battler, TRUE); + if (IS_BATTLER_OF_TYPE(battler, TYPE_GHOST) + || (switching && holdEffect == HOLD_EFFECT_SHED_SHELL) + || (!switching && GetBattlerAbility(battler) == ABILITY_RUN_AWAY) + || (!switching && holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)) + { + return FALSE; + } + else + { + if (gBattleMons[battler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED) + || IsAbilityPreventingEscape(battler) + || gStatuses3[battler] & (STATUS3_ROOTED) // TODO: sky drop target in air + || (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK)) + return TRUE; + } + + return FALSE; +} \ No newline at end of file