Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removes duplicate code in AI functions #5457

Merged
merged 15 commits into from
Oct 9, 2024
Merged
2 changes: 1 addition & 1 deletion include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ struct AiLogicData
bool8 ejectButtonSwitch; // Tracks whether current switch out was from Eject Button
bool8 ejectPackSwitch; // Tracks whether current switch out was from Eject Pack
u8 shouldSwitch; // Stores result of ShouldSwitch, which decides whether a mon should be switched out
u8 aiCalcInProgress:1;
};

struct AI_ThinkingStruct
Expand Down Expand Up @@ -715,7 +716,6 @@ struct BattleStruct
} multiBuffer;
u8 wishPerishSongState;
u8 wishPerishSongBattlerId;
u8 aiCalcInProgress:1;
u8 overworldWeatherDone:1;
u8 startingStatusDone:1;
u8 isAtkCancelerForCalledMove:1; // Certain cases in atk canceler should only be checked once, when the original move is called, however others need to be checked the twice.
Expand Down
20 changes: 20 additions & 0 deletions include/battle_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@
#define MOVE_LIMITATION_PLACEHOLDER (1 << 15)
#define MOVE_LIMITATIONS_ALL 0xFFFF

enum MoveBlocked
{
MOVE_BLOCKED_BY_NO_ABILITY,
MOVE_BLOCKED_BY_SOUNDPROOF_OR_BULLETPROOF,
MOVE_BLOCKED_BY_DAZZLING,
MOVE_BLOCKED_BY_PARTNER_DAZZLING,
MOVE_BLOCKED_BY_GOOD_AS_GOLD,
};

enum MoveAbsorbed
{
MOVE_ABSORBED_BY_NO_ABILITY,
MOVE_ABSORBED_BY_DRAIN_HP_ABILITY,
MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY,
MOVE_ABSORBED_BY_BOOST_FLASH_FIRE,
};

enum {
ABILITYEFFECT_ON_SWITCHIN,
ABILITYEFFECT_ENDTURN,
Expand Down Expand Up @@ -161,6 +178,9 @@ void SetAtkCancellerForCalledMove(void);
u8 AtkCanceller_UnableToUseMove2(void);
bool32 HasNoMonsToSwitch(u32 battler, u8 r1, u8 r2);
bool32 TryChangeBattleWeather(u32 battler, u32 weatherEnumId, bool32 viaAbility);
u32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef);
u32 CanPartnerAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef);
u32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType);
u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg);
bool32 TryPrimalReversion(u32 battler);
bool32 IsNeutralizingGasOnField(void);
Expand Down
47 changes: 9 additions & 38 deletions src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,12 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// target ability checks
if (!DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
{
if (CanAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[battlerDef]))
RETURN_SCORE_MINUS(20);

if (CanAbilityAbsorbMove(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, moveType))
RETURN_SCORE_MINUS(20);

switch (aiData->abilities[battlerDef])
{
case ABILITY_MAGIC_GUARD:
Expand Down Expand Up @@ -903,12 +909,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
&& (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG))
RETURN_SCORE_MINUS(10);
break;
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (atkPriority > 0)
RETURN_SCORE_MINUS(10);
break;
case ABILITY_AROMA_VEIL:
if (IsAromaVeilProtectedMove(move))
RETURN_SCORE_MINUS(10);
Expand Down Expand Up @@ -972,37 +972,14 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
&& IsNonVolatileStatusMoveEffect(moveEffect))
RETURN_SCORE_MINUS(10);
break;
case ABILITY_LIGHTNING_ROD:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_MOTOR_DRIVE:
case ABILITY_VOLT_ABSORB:
if (moveType == TYPE_ELECTRIC)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_WATER_ABSORB:
case ABILITY_DRY_SKIN:
if (moveType == TYPE_WATER)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_EARTH_EATER:
if (moveType == TYPE_GROUND)
RETURN_SCORE_MINUS(20);
break;
} // def ability checks

// target partner ability checks & not attacking partner
if (isDoubleBattle)
{
if (CanPartnerAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[BATTLE_PARTNER(battlerDef)]))
RETURN_SCORE_MINUS(20);

switch (aiData->abilities[BATTLE_PARTNER(battlerDef)])
{
case ABILITY_LIGHTNING_ROD:
Expand All @@ -1029,12 +1006,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (IsAromaVeilProtectedMove(move))
RETURN_SCORE_MINUS(10);
break;
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (atkPriority > 0)
RETURN_SCORE_MINUS(10);
break;
}
} // def partner ability checks
} // ignore def ability check
Expand Down
58 changes: 15 additions & 43 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,60 +402,34 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef)
{
struct AiLogicData *aiData = AI_DATA;
u32 battlerDefAbility;
u32 partnerBattlerDefAbility;
u32 moveType = GetMoveType(move);

if (DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
{
battlerDefAbility = ABILITY_NONE;
partnerBattlerDefAbility = ABILITY_NONE;
}
else
{
battlerDefAbility = aiData->abilities[battlerDef];
partnerBattlerDefAbility = aiData->abilities[BATTLE_PARTNER(battlerDef)];
}

if (battlerDef == BATTLE_PARTNER(battlerAtk))
battlerDefAbility = aiData->abilities[battlerDef];

if (gBattleStruct->commandingDondozo & (1u << battlerDef))
return TRUE;

switch (battlerDefAbility)
{
case ABILITY_LIGHTNING_ROD:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_VOLT_ABSORB:
case ABILITY_MOTOR_DRIVE:
if (moveType == TYPE_ELECTRIC)
return TRUE;
break;
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_WATER_ABSORB:
case ABILITY_DRY_SKIN:
if (moveType == TYPE_WATER)
return TRUE;
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE)
return TRUE;
break;
case ABILITY_SOUNDPROOF:
if (gMovesInfo[move].soundMove)
return TRUE;
break;
case ABILITY_BULLETPROOF:
if (gMovesInfo[move].ballisticMove)
return TRUE;
break;
case ABILITY_SAP_SIPPER:
if (moveType == TYPE_GRASS)
return TRUE;
break;
case ABILITY_EARTH_EATER:
if (moveType == TYPE_GROUND)
return TRUE;
break;
}
if (CanAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[battlerDef]))
return TRUE;

if (CanPartnerAbilityBlockMove(battlerAtk, battlerDef, move, partnerBattlerDefAbility))
return TRUE;

if (CanAbilityAbsorbMove(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, moveType))
return TRUE;

switch (gMovesInfo[move].effect)
{
Expand Down Expand Up @@ -526,7 +500,6 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
bool32 isDamageMoveUnusable = FALSE;
bool32 toggledGimmick = FALSE;
struct AiLogicData *aiData = AI_DATA;
gBattleStruct->aiCalcInProgress = TRUE;

if (moveEffect == EFFECT_NATURE_POWER)
move = GetNaturePowerMove(battlerAtk);
Expand Down Expand Up @@ -736,7 +709,6 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
*typeEffectiveness = AI_GetEffectiveness(effectivenessMultiplier);

// Undo temporary settings
gBattleStruct->aiCalcInProgress = FALSE;
gBattleStruct->swapDamageCategory = FALSE;
gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE;
if (toggledGimmick)
Expand Down
3 changes: 3 additions & 0 deletions src/battle_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4198,7 +4198,10 @@ static void HandleTurnActionSelectionState(void)
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, TRUE);
else
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, FALSE);

AI_DATA->aiCalcInProgress = TRUE;
gBattleStruct->aiMoveOrAction[battler] = ComputeBattleAiScores(battler);
AI_DATA->aiCalcInProgress = FALSE;
AlexOn1ine marked this conversation as resolved.
Show resolved Hide resolved
}
// fallthrough
case STATE_BEFORE_ACTION_CHOSEN: // Choose an action.
Expand Down
Loading
Loading