Add ShouldSwitch result to AiLogicData (#5440)

* Add ShouldSwitch to AiLogicData

* Convert shouldSwitch to bitfield

* Update include/battle.h

Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>

* Update include/battle.h

---------

Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>
This commit is contained in:
Pawkkie 2024-09-29 12:16:33 -04:00 committed by GitHub
parent 5130ea9da3
commit 5e027754c7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 12 additions and 11 deletions

View file

@ -366,11 +366,12 @@ struct AiLogicData
u8 effectiveness[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
u8 moveAccuracy[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
u8 moveLimitations[MAX_BATTLERS_COUNT];
bool8 shouldSwitchMon; // Because all available moves have no/little effect. Each bit per battler.
u8 shouldSwitchIfBadMoves; // Because all available moves have no/little effect. Each bit per battler.
u8 monToSwitchId[MAX_BATTLERS_COUNT]; // ID of the mon to switch.
bool8 weatherHasEffect; // The same as WEATHER_HAS_EFFECT. Stored here, so it's called only once.
u8 mostSuitableMonId[MAX_BATTLERS_COUNT]; // Stores result of GetMostSuitableMonToSwitchInto, which decides which generic mon the AI would switch into if they decide to switch. This can be overruled by specific mons found in ShouldSwitch; the final resulting mon is stored in AI_monToSwitchIntoId.
struct SwitchinCandidate switchinCandidate; // Struct used for deciding which mon to switch to in battle_ai_switch_items.c
u8 shouldSwitch; // Stores result of ShouldSwitch, which decides whether a mon should be switched out
};
struct AI_ThinkingStruct

View file

@ -504,12 +504,12 @@ static bool32 AI_SwitchMonIfSuitable(u32 battler, bool32 doubleBattle)
if (doubleBattle)
{
u32 partner = BATTLE_PARTNER(battler);
if (AI_DATA->shouldSwitchMon & (1u << partner) && AI_DATA->monToSwitchId[partner] == monToSwitchId)
if (AI_DATA->shouldSwitchIfBadMoves & (1u << partner) && AI_DATA->monToSwitchId[partner] == monToSwitchId)
{
return FALSE;
}
}
AI_DATA->shouldSwitchMon |= 1 << battler;
AI_DATA->shouldSwitchIfBadMoves |= 1 << battler;
AI_DATA->monToSwitchId[battler] = monToSwitchId;
return TRUE;
}
@ -3679,7 +3679,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
}
break;
case EFFECT_BATON_PASS:
if (ShouldSwitch(battlerAtk, FALSE) && (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE
if ((AI_DATA->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);

View file

@ -218,9 +218,9 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
static bool32 ShouldSwitchIfAllBadMoves(u32 battler, bool32 emitResult)
{
if (AI_DATA->shouldSwitchMon & (1u << battler))
if (AI_DATA->shouldSwitchIfBadMoves & (1u << battler))
{
AI_DATA->shouldSwitchMon &= ~(1u << battler);
AI_DATA->shouldSwitchIfBadMoves &= ~(1u << battler);
gBattleStruct->AI_monToSwitchIntoId[battler] = AI_DATA->monToSwitchId[battler];
if (emitResult)
BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SWITCH, 0);

View file

@ -2699,10 +2699,8 @@ enum {
bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex)
{
bool32 hasStatBoost = AnyUsefulStatIsRaised(battlerAtk) || gBattleMons[battlerDef].statStages[STAT_EVASION] >= 9; //Significant boost in evasion for any class
bool32 shouldSwitch;
u32 battlerToSwitch;
shouldSwitch = ShouldSwitch(battlerAtk, FALSE);
battlerToSwitch = gBattleStruct->AI_monToSwitchIntoId[battlerAtk];
if (PartyBattlerShouldAvoidHazards(battlerAtk, battlerToSwitch))
@ -2727,7 +2725,7 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
if (CanTargetFaintAi(battlerDef, battlerAtk))
return PIVOT; // Won't get the two turns, pivot
if (!IS_MOVE_STATUS(move) && (shouldSwitch
if (!IS_MOVE_STATUS(move) && ((AI_DATA->shouldSwitch & (1u << battlerAtk))
|| (AtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|| (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY)
|| defAbility == ABILITY_MULTISCALE
@ -2742,7 +2740,7 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
|| defAbility == ABILITY_SHADOW_SHIELD)))
return PIVOT; // pivot to break sash/sturdy/multiscale
if (shouldSwitch)
if (AI_DATA->shouldSwitch & (1u << battlerAtk))
return PIVOT;
/* TODO - check if switchable mon unafffected by/will remove hazards
@ -2813,7 +2811,7 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
else if (CanAIFaintTarget(battlerAtk, battlerDef, 2))
{
// can knock out foe in 2 hits
if (IS_MOVE_STATUS(move) && (shouldSwitch //Damaging move
if (IS_MOVE_STATUS(move) && ((AI_DATA->shouldSwitch & (1u << battlerAtk)) //Damaging move
//&& (switchScore >= SWITCHING_INCREASE_RESIST_ALL_MOVES + SWITCHING_INCREASE_KO_FOE //remove hazards
|| (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef))))
return DONT_PIVOT; // Pivot to break the sash

View file

@ -4178,6 +4178,8 @@ static void HandleTurnActionSelectionState(void)
if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart())
&& (BattlerHasAi(battler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE)))
{
if (ShouldSwitch(battler, FALSE))
AI_DATA->shouldSwitch |= (1u << battler);
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_RISKY) // Risky AI switches aggressively even mid battle
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, TRUE);
else