Remove Duplicate ai code from battle_ai_util.c (#4883)
* Remove Duplicate ai code from battle_ai_util.c * Add GetBattlerAbility in toxic self check
This commit is contained in:
parent
d81662daa2
commit
594633aa15
@ -134,10 +134,8 @@ bool32 HasMagicCoatAffectedMove(u32 battler);
|
||||
bool32 HasSnatchAffectedMove(u32 battler);
|
||||
|
||||
// status checks
|
||||
bool32 AI_CanBeBurned(u32 battler, u32 ability);
|
||||
bool32 AI_CanGetFrostbite(u32 battler, u32 ability);
|
||||
bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability);
|
||||
bool32 AI_CanSleep(u32 battler, u32 ability);
|
||||
bool32 IsBattlerIncapacitated(u32 battler, u32 ability);
|
||||
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
|
||||
bool32 ShouldPoisonSelf(u32 battler, u32 ability);
|
||||
|
||||
@ -235,10 +235,10 @@ bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect);
|
||||
bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument);
|
||||
bool32 MoveHasChargeTurnAdditionalEffect(u32 move);
|
||||
|
||||
bool32 CanSleep(u32 battler);
|
||||
bool32 CanBePoisoned(u32 battlerAttacker, u32 battlerTarget);
|
||||
bool32 CanBeBurned(u32 battler);
|
||||
bool32 CanBeParalyzed(u32 battler);
|
||||
bool32 CanBeSlept(u32 battler, u32 ability);
|
||||
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
bool32 CanBeBurned(u32 battler, u32 ability);
|
||||
bool32 CanBeParalyzed(u32 battler, u32 ability);
|
||||
bool32 CanBeFrozen(u32 battler);
|
||||
bool32 CanGetFrostbite(u32 battler);
|
||||
bool32 CanBeConfused(u32 battler);
|
||||
|
||||
@ -1866,7 +1866,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_REST:
|
||||
if (!AI_CanSleep(battlerAtk, aiData->abilities[battlerAtk]))
|
||||
if (!CanBeSlept(battlerAtk, aiData->abilities[battlerAtk]))
|
||||
ADJUST_SCORE(-10);
|
||||
//fallthrough
|
||||
case EFFECT_RESTORE_HP:
|
||||
@ -3456,7 +3456,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
break;
|
||||
case EFFECT_REST:
|
||||
if (!(AI_CanSleep(battlerAtk, aiData->abilities[battlerAtk])))
|
||||
if (!(CanBeSlept(battlerAtk, aiData->abilities[battlerAtk])))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -3936,7 +3936,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_FLAME_ORB:
|
||||
if (!ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk]) && AI_CanBeBurned(battlerAtk, aiData->abilities[battlerDef]))
|
||||
if (!ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk]) && CanBeBurned(battlerAtk, aiData->abilities[battlerDef]))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||
|
||||
@ -442,7 +442,7 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
|
||||
{
|
||||
//Yawn
|
||||
if (gStatuses3[battler] & STATUS3_YAWN
|
||||
&& AI_CanSleep(battler, monAbility)
|
||||
&& CanBeSlept(battler, monAbility)
|
||||
&& gBattleMons[battler].hp > gBattleMons[battler].maxHP / 3)
|
||||
{
|
||||
switchMon = TRUE;
|
||||
@ -1291,8 +1291,6 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon
|
||||
hazardDamage += spikesDamage;
|
||||
}
|
||||
|
||||
// Toxic Spikes
|
||||
// TODO: CanBePoisoned compatibility to avoid duplicate code
|
||||
if ((hazardFlags & SIDE_STATUS_TOXIC_SPIKES) && (defType1 != TYPE_POISON && defType2 != TYPE_POISON
|
||||
&& defType1 != TYPE_STEEL && defType2 != TYPE_STEEL
|
||||
&& ability != ABILITY_IMMUNITY && ability != ABILITY_POISON_HEAL && ability != ABILITY_COMATOSE
|
||||
|
||||
@ -2624,48 +2624,18 @@ bool32 IsBattlerIncapacitated(u32 battler, u32 ability)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 AI_CanSleep(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability == ABILITY_INSOMNIA
|
||||
|| ability == ABILITY_VITAL_SPIRIT
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| (gFieldStatuses & (STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN))
|
||||
|| IsAbilityStatusProtected(battler))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!AI_CanSleep(battlerDef, defAbility)
|
||||
if (!CanBeSlept(battlerDef, defAbility)
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|
||||
|| PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) // shouldn't try to sleep mon that partner is trying to make sleep
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool32 AI_CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
u32 ability = AI_DATA->abilities[battlerDef];
|
||||
|
||||
if (!(CanPoisonType(battlerAtk, battlerDef))
|
||||
|| gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battlerDef].status1 & STATUS1_ANY
|
||||
|| ability == ABILITY_IMMUNITY
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| AI_IsAbilityOnSide(battlerDef, ABILITY_PASTEL_VEIL)
|
||||
|| gBattleMons[battlerDef].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battlerDef)
|
||||
|| AI_IsTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 ShouldPoisonSelf(u32 battler, u32 ability)
|
||||
{
|
||||
if (AI_CanBePoisoned(battler, battler, 0) && (
|
||||
if (CanBePoisoned(battler, battler, GetBattlerAbility(battler)) && (
|
||||
ability == ABILITY_MARVEL_SCALE
|
||||
|| ability == ABILITY_POISON_HEAL
|
||||
|| ability == ABILITY_QUICK_FEET
|
||||
@ -2680,7 +2650,7 @@ bool32 ShouldPoisonSelf(u32 battler, u32 ability)
|
||||
|
||||
bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!AI_CanBePoisoned(battlerAtk, battlerDef, move)
|
||||
if (!CanBePoisoned(battlerAtk, battlerDef, GetBattlerAbility(battlerDef))
|
||||
|| AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|
||||
|| PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove))
|
||||
@ -2693,20 +2663,9 @@ bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u3
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool32 AI_CanBeParalyzed(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability == ABILITY_LIMBER
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC)
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!AI_CanBeParalyzed(battlerDef, defAbility)
|
||||
if (!CanBeParalyzed(battlerDef, defAbility)
|
||||
|| AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0
|
||||
|| gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|
||||
@ -2740,19 +2699,6 @@ bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battler
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 AI_CanBeBurned(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability == ABILITY_WATER_VEIL
|
||||
|| ability == ABILITY_WATER_BUBBLE
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| IS_BATTLER_OF_TYPE(battler, TYPE_FIRE)
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 AI_CanGetFrostbite(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability == ABILITY_MAGMA_ARMOR
|
||||
@ -2767,7 +2713,7 @@ bool32 AI_CanGetFrostbite(u32 battler, u32 ability)
|
||||
|
||||
bool32 ShouldBurnSelf(u32 battler, u32 ability)
|
||||
{
|
||||
if (AI_CanBeBurned(battler, ability) && (
|
||||
if (CanBeBurned(battler, ability) && (
|
||||
ability == ABILITY_QUICK_FEET
|
||||
|| ability == ABILITY_HEATPROOF
|
||||
|| ability == ABILITY_MAGIC_GUARD
|
||||
@ -2781,7 +2727,7 @@ bool32 ShouldBurnSelf(u32 battler, u32 ability)
|
||||
|
||||
bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!AI_CanBeBurned(battlerDef, defAbility)
|
||||
if (!CanBeBurned(battlerDef, defAbility)
|
||||
|| AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|
||||
|| PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove))
|
||||
|
||||
@ -791,7 +791,7 @@ void BS_SetMaxMoveEffect(void)
|
||||
{
|
||||
static const u8 sSnoozeEffects[] = {TRUE, FALSE};
|
||||
if (!(gStatuses3[gBattlerTarget] & STATUS3_YAWN)
|
||||
&& CanSleep(gBattlerTarget)
|
||||
&& CanBeSlept(gBattlerTarget, GetBattlerAbility(gBattlerTarget))
|
||||
&& RandomElement(RNG_G_MAX_SNOOZE, sSnoozeEffects)) // 50% chance of success
|
||||
{
|
||||
gStatuses3[gBattlerTarget] |= STATUS3_YAWN_TURN(2);
|
||||
@ -897,7 +897,7 @@ void BS_TrySetStatus1(void)
|
||||
switch (status1)
|
||||
{
|
||||
case STATUS1_POISON:
|
||||
if (CanBePoisoned(gBattlerAttacker, gBattlerTarget))
|
||||
if (CanBePoisoned(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget)))
|
||||
{
|
||||
gBattleMons[gBattlerTarget].status1 |= STATUS1_POISON;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
||||
@ -905,7 +905,7 @@ void BS_TrySetStatus1(void)
|
||||
}
|
||||
break;
|
||||
case STATUS1_PARALYSIS:
|
||||
if (CanBeParalyzed(gBattlerTarget))
|
||||
if (CanBeParalyzed(gBattlerTarget, GetBattlerAbility(gBattlerTarget)))
|
||||
{
|
||||
gBattleMons[gBattlerTarget].status1 |= STATUS1_PARALYSIS;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
|
||||
@ -913,7 +913,7 @@ void BS_TrySetStatus1(void)
|
||||
}
|
||||
break;
|
||||
case STATUS1_SLEEP:
|
||||
if (CanSleep(gBattlerTarget))
|
||||
if (CanBeSlept(gBattlerTarget, GetBattlerAbility(gBattlerTarget)))
|
||||
{
|
||||
if (B_SLEEP_TURNS >= GEN_5)
|
||||
gBattleMons[gBattlerTarget].status1 |= STATUS1_SLEEP_TURN((Random() % 3) + 2);
|
||||
|
||||
@ -2907,7 +2907,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
|
||||
if (i != gBattlersCount)
|
||||
break;
|
||||
if (!CanSleep(gEffectBattler))
|
||||
if (!CanBeSlept(gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
break;
|
||||
|
||||
cancelMultiTurnMovesResult = CancelMultiTurnMoves(gEffectBattler);
|
||||
@ -2946,7 +2946,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STATUS_HAD_NO_EFFECT;
|
||||
RESET_RETURN
|
||||
}
|
||||
if (!CanBePoisoned(gBattleScripting.battler, gEffectBattler))
|
||||
if (!CanBePoisoned(gBattleScripting.battler, gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
break;
|
||||
|
||||
statusChanged = TRUE;
|
||||
@ -2990,7 +2990,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!CanBeBurned(gEffectBattler))
|
||||
if (!CanBeBurned(gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
break;
|
||||
|
||||
statusChanged = TRUE;
|
||||
@ -3055,7 +3055,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
}
|
||||
if (!CanParalyzeType(gBattleScripting.battler, gEffectBattler))
|
||||
break;
|
||||
if (!CanBeParalyzed(gEffectBattler))
|
||||
if (!CanBeParalyzed(gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
break;
|
||||
|
||||
statusChanged = TRUE;
|
||||
@ -3093,7 +3093,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
}
|
||||
if (gBattleMons[gEffectBattler].status1)
|
||||
break;
|
||||
if (CanBePoisoned(gBattleScripting.battler, gEffectBattler))
|
||||
if (CanBePoisoned(gBattleScripting.battler, gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
{
|
||||
// It's redundant, because at this point we know the status1 value is 0.
|
||||
gBattleMons[gEffectBattler].status1 &= ~STATUS1_TOXIC_POISON;
|
||||
@ -5514,7 +5514,7 @@ static void Cmd_moveend(void)
|
||||
}
|
||||
// Not strictly a protect effect, but works the same way
|
||||
else if (gProtectStructs[gBattlerTarget].beakBlastCharge
|
||||
&& CanBeBurned(gBattlerAttacker)
|
||||
&& CanBeBurned(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
|
||||
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
@ -9940,16 +9940,17 @@ static void Cmd_various(void)
|
||||
case VARIOUS_PSYCHO_SHIFT:
|
||||
{
|
||||
VARIOUS_ARGS(const u8 *failInstr);
|
||||
u32 targetAbility = GetBattlerAbility(gBattlerTarget);
|
||||
// Psycho shift works
|
||||
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_POISON) && CanBePoisoned(gBattlerAttacker, gBattlerTarget))
|
||||
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_POISON) && CanBePoisoned(gBattlerAttacker, gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_TOXIC_POISON) && CanBePoisoned(gBattlerAttacker, gBattlerTarget))
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_TOXIC_POISON) && CanBePoisoned(gBattlerAttacker, gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_BURN) && CanBeBurned(gBattlerTarget))
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_BURN) && CanBeBurned(gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && CanBeParalyzed(gBattlerTarget))
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && CanBeParalyzed(gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) && CanSleep(gBattlerTarget))
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) && CanBeSlept(gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE) && CanBeFrozen(gBattlerTarget))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 5;
|
||||
|
||||
@ -5455,8 +5455,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
}
|
||||
break;
|
||||
case ABILITY_EFFECT_SPORE:
|
||||
{
|
||||
u32 ability = GetBattlerAbility(gBattlerAttacker);
|
||||
if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GRASS)
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_OVERCOAT
|
||||
&& ability != ABILITY_OVERCOAT
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES)
|
||||
{
|
||||
i = Random() % 3;
|
||||
@ -5469,7 +5471,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& gBattleMons[gBattlerAttacker].hp != 0
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& TARGET_TURN_DAMAGED
|
||||
&& CanSleep(gBattlerAttacker)
|
||||
&& CanBeSlept(gBattlerAttacker, ability)
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& IsMoveMakingContact(move, gBattlerAttacker)
|
||||
&& (Random() % 3) == 0)
|
||||
@ -5482,6 +5484,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
effect++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
POISON_POINT:
|
||||
case ABILITY_POISON_POINT:
|
||||
@ -5489,7 +5492,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& gBattleMons[gBattlerAttacker].hp != 0
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& TARGET_TURN_DAMAGED
|
||||
&& CanBePoisoned(gBattlerTarget, gBattlerAttacker)
|
||||
&& CanBePoisoned(gBattlerTarget, gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& IsMoveMakingContact(move, gBattlerAttacker)
|
||||
&& RandomWeighted(RNG_POISON_POINT, 2, 1))
|
||||
@ -5508,7 +5511,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& gBattleMons[gBattlerAttacker].hp != 0
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& TARGET_TURN_DAMAGED
|
||||
&& CanBeParalyzed(gBattlerAttacker)
|
||||
&& CanBeParalyzed(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& IsMoveMakingContact(move, gBattlerAttacker)
|
||||
&& RandomWeighted(RNG_STATIC, 2, 1))
|
||||
@ -5528,7 +5531,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& (IsMoveMakingContact(move, gBattlerAttacker))
|
||||
&& TARGET_TURN_DAMAGED
|
||||
&& CanBeBurned(gBattlerAttacker)
|
||||
&& CanBeBurned(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
|
||||
&& RandomWeighted(RNG_FLAME_BODY, 2, 1))
|
||||
{
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN;
|
||||
@ -5745,7 +5748,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
||||
&& gBattleMons[gBattlerTarget].hp != 0
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget)
|
||||
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget))
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& IsMoveMakingContact(move, gBattlerAttacker)
|
||||
&& TARGET_TURN_DAMAGED // Need to actually hit the target
|
||||
@ -6327,83 +6330,78 @@ bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag)
|
||||
return IsBattlerGrounded(battler);
|
||||
}
|
||||
|
||||
bool32 CanSleep(u32 battler)
|
||||
bool32 CanBeSlept(u32 battler, u32 ability)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battler);
|
||||
if (ability == ABILITY_INSOMNIA
|
||||
|| ability == ABILITY_VITAL_SPIRIT
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityOnSide(battler, ABILITY_SWEET_VEIL)
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBePoisoned(u32 battlerAttacker, u32 battlerTarget)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battlerTarget);
|
||||
|
||||
if (!(CanPoisonType(battlerAttacker, battlerTarget))
|
||||
|| gSideStatuses[GetBattlerSide(battlerTarget)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battlerTarget].status1 & STATUS1_ANY
|
||||
|| ability == ABILITY_IMMUNITY
|
||||
|| ability == ABILITY_VITAL_SPIRIT
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| IsAbilityOnSide(battlerTarget, ABILITY_PASTEL_VEIL)
|
||||
|| IsAbilityStatusProtected(battlerTarget)
|
||||
|| IsBattlerTerrainAffected(battlerTarget, STATUS_FIELD_MISTY_TERRAIN))
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityOnSide(battler, ABILITY_SWEET_VEIL)
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeBurned(u32 battler)
|
||||
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (!(CanPoisonType(battlerAtk, battlerDef))
|
||||
|| gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battlerDef].status1 & STATUS1_ANY
|
||||
|| defAbility == ABILITY_IMMUNITY
|
||||
|| defAbility == ABILITY_COMATOSE
|
||||
|| defAbility == ABILITY_PURIFYING_SALT
|
||||
|| IsAbilityOnSide(battlerDef, ABILITY_PASTEL_VEIL)
|
||||
|| IsAbilityStatusProtected(battlerDef)
|
||||
|| IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeBurned(u32 battler, u32 ability)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battler);
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_FIRE)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| ability == ABILITY_WATER_VEIL
|
||||
|| ability == ABILITY_WATER_BUBBLE
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_THERMAL_EXCHANGE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeParalyzed(u32 battler, u32 ability)
|
||||
{
|
||||
if ((B_PARALYZE_ELECTRIC >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC))
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| ability == ABILITY_WATER_VEIL
|
||||
|| ability == ABILITY_WATER_BUBBLE
|
||||
|| ability == ABILITY_LIMBER
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_THERMAL_EXCHANGE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeParalyzed(u32 battler)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battler);
|
||||
if ((B_PARALYZE_ELECTRIC >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC))
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| ability == ABILITY_LIMBER
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeFrozen(u32 battler)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battler);
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_ICE)
|
||||
|| IsBattlerWeatherAffected(battler, B_WEATHER_SUN)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| ability == ABILITY_MAGMA_ARMOR
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
|| IsBattlerWeatherAffected(battler, B_WEATHER_SUN)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| ability == ABILITY_MAGMA_ARMOR
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
@ -6426,8 +6424,8 @@ bool32 CanGetFrostbite(u32 battler)
|
||||
bool32 CanBeConfused(u32 battler)
|
||||
{
|
||||
if (GetBattlerAbility(battler) == ABILITY_OWN_TEMPO
|
||||
|| gBattleMons[battler].status2 & STATUS2_CONFUSION
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
|| gBattleMons[battler].status2 & STATUS2_CONFUSION
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
@ -7907,7 +7905,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
|
||||
switch (battlerHoldEffect)
|
||||
{
|
||||
case HOLD_EFFECT_TOXIC_ORB:
|
||||
if (CanBePoisoned(battler, battler))
|
||||
if (CanBePoisoned(battler, battler, GetBattlerAbility(battler)))
|
||||
{
|
||||
effect = ITEM_STATUS_CHANGE;
|
||||
gBattleMons[battler].status1 = STATUS1_TOXIC_POISON;
|
||||
@ -7916,7 +7914,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_FLAME_ORB:
|
||||
if (CanBeBurned(battler))
|
||||
if (CanBeBurned(battler, battlerAbility))
|
||||
{
|
||||
effect = ITEM_STATUS_CHANGE;
|
||||
gBattleMons[battler].status1 = STATUS1_BURN;
|
||||
@ -8185,7 +8183,7 @@ u8 IsMonDisobedient(void)
|
||||
obedienceLevel = levelReferenced - obedienceLevel;
|
||||
|
||||
calc = (Random() & 255);
|
||||
if (calc < obedienceLevel && CanSleep(gBattlerAttacker))
|
||||
if (calc < obedienceLevel && CanBeSlept(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)))
|
||||
{
|
||||
// try putting asleep
|
||||
int i;
|
||||
|
||||
@ -56,6 +56,23 @@ SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the user")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Own Tempo is ignored by Mold Breaker")
|
||||
{
|
||||
KNOWN_FAILING; // Ideally the func CanBeConfused should be split into AttackerCanBeConfused and TargetCanBeConfused or we do it in the same func but have a check for when battlerAtk == battlerDef
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE);
|
||||
PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); }
|
||||
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); };
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CONFUSE_RAY); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_OWN_TEMPO);
|
||||
MESSAGE("Foe Slowpoke's Own Tempo prevents confusion!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Own Tempo cures confusion obtained from an opponent with Mold Breaker")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
|
||||
@ -1039,3 +1039,4 @@ AI_SINGLE_BATTLE_TEST("AI avoids contact moves against rocky helmet")
|
||||
TURN { EXPECT_MOVES(opponent, MOVE_LEAFAGE, MOVE_BRANCH_POKE); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -48,3 +48,21 @@ SINGLE_BATTLE_TEST("Toxic cannot miss if used by a Poison-type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids toxic when it can not poison target")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_SNORLAX; ability = ABILITY_IMMUNITY; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
PARAMETRIZE { species = SPECIES_BULBASAUR; ability = ABILITY_OVERGROW; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_TOXIC); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_TOXIC); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,3 +35,23 @@ SINGLE_BATTLE_TEST("Burn reduces Attack by 50%", s16 damage)
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids Will-o-Wisp when it can not burn target")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_BUIZEL; ability = ABILITY_WATER_VEIL; }
|
||||
PARAMETRIZE { species = SPECIES_DEWPIDER; ability = ABILITY_WATER_BUBBLE; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_ARCTIBAX; ability = ABILITY_THERMAL_EXCHANGE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
PARAMETRIZE { species = SPECIES_CHARMANDER; ability = ABILITY_BLAZE; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_WILL_O_WISP); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_WILL_O_WISP); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,3 +42,21 @@ SINGLE_BATTLE_TEST("Paralysis has a 25% chance of skipping the turn")
|
||||
MESSAGE("Wobbuffet is paralyzed! It can't move!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids Thunder Wave when it can not paralyse target")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_HITMONLEE; ability = ABILITY_LIMBER; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
PARAMETRIZE { species = SPECIES_PIKACHU; ability = ABILITY_STATIC; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_THUNDER_WAVE); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_THUNDER_WAVE); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,3 +21,21 @@ SINGLE_BATTLE_TEST("Sleep prevents the battler from using a move")
|
||||
MESSAGE("Wobbuffet used Celebrate!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids hypnosis when it can not put target to sleep")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_HOOTHOOT; ability = ABILITY_INSOMNIA; }
|
||||
PARAMETRIZE { species = SPECIES_MANKEY; ability = ABILITY_VITAL_SPIRIT; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_HYPNOSIS); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_HYPNOSIS); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user