Fixed Belly Drum/Contrary interaction at max Attack (#8078)

This commit is contained in:
Eduardo Quezada 2025-10-30 13:14:07 -03:00 committed by GitHub
parent c77c624e9f
commit 8de86ba243
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 84 additions and 60 deletions

View File

@ -187,8 +187,13 @@
.4byte \jumpInstr
.endm
.macro unused_0x21
.macro jumpifstatignorecontrary battler:req, comparison:req, stat:req, value:req, jumpInstr:req
.byte 0x21
.byte \battler
.byte \comparison
.byte \stat
.byte \value
.4byte \jumpInstr
.endm
.macro jumpbasedontype battler:req, type:req, jumpIfType:req, jumpInstr:req

View File

@ -4221,7 +4221,7 @@ BattleScript_EffectBellyDrum::
attackcanceler
attackstring
ppreduce
jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_ButItFailed
jumpifstatignorecontrary BS_ATTACKER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_ButItFailed
halvehp BattleScript_ButItFailed
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE
attackanimation

View File

@ -332,7 +332,7 @@ bool32 IsPartnerMonFromSameTrainer(u32 battler);
enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, u32 statId, u32 itemId, enum ItemCaseId caseID);
bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes);
void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast);
bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind);
bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind, u32 ability);
bool32 TryRoomService(u32 battler);
void BufferStatChange(u32 battler, u8 statId, enum StringID stringId);
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget);

View File

@ -370,7 +370,7 @@ static void Cmd_jumpifvolatile(void);
static void Cmd_jumpifability(void);
static void Cmd_jumpifsideaffecting(void);
static void Cmd_jumpifstat(void);
static void Cmd_unused_0x21(void);
static void Cmd_jumpifstatignorecontrary(void);
static void Cmd_jumpbasedontype(void);
static void Cmd_getexp(void);
static void Cmd_checkteamslost(void);
@ -629,7 +629,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
Cmd_jumpifability, //0x1E
Cmd_jumpifsideaffecting, //0x1F
Cmd_jumpifstat, //0x20
Cmd_unused_0x21, //0x21
Cmd_jumpifstatignorecontrary, //0x21
Cmd_jumpbasedontype, //0x22
Cmd_getexp, //0x23
Cmd_checkteamslost, //0x24
@ -4432,7 +4432,7 @@ static void Cmd_jumpifstat(void)
u8 value = cmd->value;
u8 comparison = cmd->comparison;
ret = CompareStat(battler, stat, value, comparison);
ret = CompareStat(battler, stat, value, comparison, GetBattlerAbility(battler));
if (ret)
gBattlescriptCurrInstr = cmd->jumpInstr;
@ -4440,8 +4440,22 @@ static void Cmd_jumpifstat(void)
gBattlescriptCurrInstr = cmd->nextInstr;
}
static void Cmd_unused_0x21(void)
static void Cmd_jumpifstatignorecontrary(void)
{
CMD_ARGS(u8 battler, u8 comparison, u8 stat, u8 value, const u8 *jumpInstr);
bool32 ret = 0;
u8 battler = GetBattlerForBattleScript(cmd->battler);
u8 stat = cmd->stat;
u8 value = cmd->value;
u8 comparison = cmd->comparison;
ret = CompareStat(battler, stat, value, comparison, ABILITY_NONE);
if (ret)
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
}
static void Cmd_jumpbasedontype(void)
@ -5620,7 +5634,7 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move
else if (abilityAtk == ABILITY_GRIM_NEIGH || abilityAtk == ABILITY_AS_ONE_SHADOW_RIDER)
stat = STAT_SPATK;
if (numMonsFainted && CompareStat(battlerAtk, stat, MAX_STAT_STAGE, CMP_LESS_THAN))
if (numMonsFainted && CompareStat(battlerAtk, stat, MAX_STAT_STAGE, CMP_LESS_THAN, abilityAtk))
{
gLastUsedAbility = abilityAtk;
if (abilityAtk == ABILITY_AS_ONE_ICE_RIDER)
@ -5660,17 +5674,17 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move
else
{
u32 numStatBuffs = 0;
if (CompareStat(battlerAtk, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(battlerAtk, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, abilityAtk))
{
gBattleScripting.animArg1 = GET_STAT_BUFF_ID(STAT_ATK) + STAT_ANIM_PLUS1;
numStatBuffs++;
}
if (CompareStat(battlerAtk, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(battlerAtk, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, abilityAtk))
{
gBattleScripting.animArg1 = GET_STAT_BUFF_ID(STAT_SPATK) + STAT_ANIM_PLUS1;
numStatBuffs++;
}
if (CompareStat(battlerAtk, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(battlerAtk, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, abilityAtk))
{
gBattleScripting.animArg1 = GET_STAT_BUFF_ID(STAT_SPEED) + STAT_ANIM_PLUS1;
numStatBuffs++;
@ -5876,7 +5890,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
&& !IsBattlerAlive(gBattlerTarget)
&& IsBattlerTurnDamaged(gBattlerTarget)
&& !NoAliveMonsForEitherParty()
&& CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerAttacker)))
{
SET_STATCHANGER(STAT_ATK, GetGenConfig(GEN_CONFIG_FELL_STINGER_STAT_RAISE) >= GEN_7 ? 3 : 2, FALSE);
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK);
@ -6106,7 +6120,7 @@ static void Cmd_moveend(void)
&& !IsBattlerAlly(gBattlerAttacker, gBattlerTarget)
&& IsBattlerTurnDamaged(gBattlerTarget)
&& !IsBattleMoveStatus(gCurrentMove)
&& CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerTarget)))
{
SET_STATCHANGER(STAT_ATK, 1, FALSE);
BattleScriptCall(BattleScript_RageIsBuilding);
@ -6522,7 +6536,7 @@ static void Cmd_moveend(void)
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_THROAT_SPRAY
&& IsBattlerAlive(gBattlerAttacker)
&& IsAnyTargetAffected(gBattlerAttacker)
&& CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)
&& CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerAttacker))
&& !NoAliveMonsForEitherParty()) // Don't activate if battle will end
{
gLastUsedItem = gBattleMons[gBattlerAttacker].item;
@ -12089,7 +12103,7 @@ static void Cmd_jumpifconfusedandstatmaxed(void)
CMD_ARGS(u8 stat, const u8 *jumpInstr);
if (gBattleMons[gBattlerTarget].volatiles.confusionTurns > 0
&& !CompareStat(gBattlerTarget, cmd->stat, MAX_STAT_STAGE, CMP_LESS_THAN))
&& !CompareStat(gBattlerTarget, cmd->stat, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerTarget)))
gBattlescriptCurrInstr = cmd->jumpInstr; // Fails if we're confused AND stat cannot be raised
else
gBattlescriptCurrInstr = cmd->nextInstr;
@ -16014,7 +16028,7 @@ void BS_CanTarShotWork(void)
NATIVE_ARGS(const u8 *failInstr);
// Tar Shot will fail if it's already been used on the target or if its speed can't be lowered further
if (!gDisableStructs[gBattlerTarget].tarShot
&& CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerTarget)))
gBattlescriptCurrInstr = cmd->nextInstr;
else
gBattlescriptCurrInstr = cmd->failInstr;
@ -16968,7 +16982,7 @@ void BS_TryAcupressure(void)
u32 bits = 0;
for (u32 stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++)
{
if (CompareStat(gBattlerTarget, stat, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(gBattlerTarget, stat, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerTarget)))
bits |= 1u << stat;
}
if (bits)
@ -17367,10 +17381,11 @@ void BS_TryActivateSoulheart(void)
while (gBattleStruct->soulheartBattlerId < gBattlersCount)
{
gBattleScripting.battler = gBattleStruct->soulheartBattlerId++;
if (GetBattlerAbility(gBattleScripting.battler) == ABILITY_SOUL_HEART
u32 ability = GetBattlerAbility(gBattleScripting.battler);
if (ability == ABILITY_SOUL_HEART
&& IsBattlerAlive(gBattleScripting.battler)
&& !NoAliveMonsForEitherParty()
&& CompareStat(gBattleScripting.battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(gBattleScripting.battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, ability))
{
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPATK);
@ -18278,10 +18293,11 @@ void BS_CutOneThirdHpAndRaiseStats(void)
bool8 atLeastOneStatBoosted = FALSE;
u16 hpFraction = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 3);
u32 ability = GetBattlerAbility(gBattlerAttacker);
for (u32 stat = 1; stat < NUM_STATS; stat++)
{
if (CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_LESS_THAN, ability))
{
atLeastOneStatBoosted = TRUE;
break;

View File

@ -1196,7 +1196,7 @@ void PrepareStringBattle(enum StringID stringId, u32 battler)
else if (GetGenConfig(GEN_CONFIG_UPDATED_INTIMIDATE) >= GEN_8
&& stringId == STRINGID_PKMNCUTSATTACKWITH
&& targetAbility == ABILITY_RATTLED
&& CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, targetAbility))
{
gBattlerAbility = gBattlerTarget;
BattleScriptCall(BattleScript_AbilityRaisesDefenderStat);
@ -1702,13 +1702,13 @@ u32 GetBattlerAffectionHearts(u32 battler)
// gBattlerAttacker is the battler that's trying to raise their stats and due to limitations of RandomUniformExcept, cannot be an argument
bool32 MoodyCantRaiseStat(u32 stat)
{
return CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_EQUAL);
return CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_EQUAL, GetBattlerAbility(gBattlerAttacker));
}
// gBattlerAttacker is the battler that's trying to lower their stats and due to limitations of RandomUniformExcept, cannot be an argument
bool32 MoodyCantLowerStat(u32 stat)
{
return stat == GET_STAT_BUFF_ID(gBattleScripting.statChanger) || CompareStat(gBattlerAttacker, stat, MIN_STAT_STAGE, CMP_EQUAL);
return stat == GET_STAT_BUFF_ID(gBattleScripting.statChanger) || CompareStat(gBattlerAttacker, stat, MIN_STAT_STAGE, CMP_EQUAL, GetBattlerAbility(gBattlerAttacker));
}
void TryToRevertMimicryAndFlags(void)
@ -3213,7 +3213,7 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32
break;
case MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY:
gBattleStruct->pledgeMove = FALSE;
if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN))
if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, abilityDef))
{
if ((gProtectStructs[battlerAtk].notFirstStrike))
battleScript = BattleScript_MonMadeMoveUseless;
@ -3776,7 +3776,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{
SET_STATCHANGER(statId, 1, FALSE);
SaveBattlerAttacker(gBattlerAttacker);
@ -3988,7 +3988,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (GetGenConfig(GEN_INTREPID_SWORD) == GEN_9)
GetBattlerPartyState(battler)->intrepidSwordBoost = TRUE;
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
if (CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{
SET_STATCHANGER(STAT_ATK, 1, FALSE);
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
@ -4003,7 +4003,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (GetGenConfig(GEN_DAUNTLESS_SHIELD) == GEN_9)
GetBattlerPartyState(battler)->dauntlessShieldBoost = TRUE;
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
if (CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{
SET_STATCHANGER(STAT_DEF, 1, FALSE);
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
@ -4013,7 +4013,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
break;
case ABILITY_WIND_RIDER:
if (!gSpecialStatuses[battler].switchInAbilityDone
&& CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)
&& CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)
&& gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TAILWIND)
{
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
@ -4149,7 +4149,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
else //ABILITY_EMBODY_ASPECT_TEAL_MASK
stat = STAT_SPEED;
if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_EQUAL))
if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_EQUAL, gLastUsedAbility))
break;
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
@ -4302,7 +4302,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_SPEED_BOOST:
if (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN) && gDisableStructs[battler].isFirstTurn != 2)
if (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && gDisableStructs[battler].isFirstTurn != 2)
{
SET_STATCHANGER(STAT_SPEED, 1, FALSE);
BattleScriptPushCursorAndCallback(BattleScript_SpeedBoostActivates);
@ -4318,9 +4318,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
for (i = STAT_ATK; i < statsNum; i++)
{
if (CompareStat(battler, i, MIN_STAT_STAGE, CMP_GREATER_THAN))
if (CompareStat(battler, i, MIN_STAT_STAGE, CMP_GREATER_THAN, gLastUsedAbility))
validToLower |= 1u << i;
if (CompareStat(battler, i, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(battler, i, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
validToRaise |= 1u << i;
}
@ -4457,7 +4457,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler)
&& moveType == TYPE_DARK
&& CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{
gEffectBattler = battler;
SET_STATCHANGER(STAT_ATK, 1, FALSE);
@ -4469,7 +4469,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler)
&& (moveType == TYPE_DARK || moveType == TYPE_BUG || moveType == TYPE_GHOST)
&& CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{
gEffectBattler = battler;
SET_STATCHANGER(STAT_SPEED, 1, FALSE);
@ -4481,7 +4481,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler)
&& moveType == TYPE_WATER
&& CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{
gEffectBattler = battler;
SET_STATCHANGER(STAT_DEF, 2, FALSE);
@ -4493,7 +4493,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (gBattlerAttacker != gBattlerTarget
&& IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(battler)
&& CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{
gEffectBattler = battler;
SET_STATCHANGER(STAT_DEF, 1, FALSE);
@ -4507,7 +4507,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& HadMoreThanHalfHpNowDoesnt(battler)
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
&& CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{
gEffectBattler = battler;
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
@ -4519,8 +4519,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler)
&& IsBattleMovePhysical(gCurrentMove)
&& (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN) // Don't activate if both Speed and Defense cannot be raised.
|| CompareStat(battler, STAT_DEF, MIN_STAT_STAGE, CMP_GREATER_THAN)))
&& (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) // Don't activate if both Speed and Defense cannot be raised.
|| CompareStat(battler, STAT_DEF, MIN_STAT_STAGE, CMP_GREATER_THAN, gLastUsedAbility)))
{
if (GetMoveEffect(gCurrentMove) == EFFECT_HIT_ESCAPE && CanBattlerSwitch(gBattlerAttacker))
gProtectStructs[battler].disableEjectPack = TRUE; // Set flag for target
@ -4597,7 +4597,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (gSpecialStatuses[battler].criticalHit
&& IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler)
&& CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{
SET_STATCHANGER(STAT_ATK, MAX_STAT_STAGE - gBattleMons[battler].statStages[STAT_ATK], FALSE);
BattleScriptCall(BattleScript_TargetsStatWasMaxedOut);
@ -4622,7 +4622,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITY_GOOEY:
case ABILITY_TANGLING_HAIR:
if (IsBattlerAlive(gBattlerAttacker)
&& (CompareStat(gBattlerAttacker, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN) || GetBattlerAbility(gBattlerAttacker) == ABILITY_MIRROR_ARMOR)
&& (CompareStat(gBattlerAttacker, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN, gLastUsedAbility) || GetBattlerAbility(gBattlerAttacker) == ABILITY_MIRROR_ARMOR)
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& IsBattlerTurnDamaged(gBattlerTarget)
&& !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move))
@ -4830,7 +4830,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITY_STEAM_ENGINE:
if (IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(battler)
&& CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)
&& CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)
&& (moveType == TYPE_FIRE || moveType == TYPE_WATER))
{
gEffectBattler = battler;
@ -4916,7 +4916,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITY_THERMAL_EXCHANGE:
if (IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(gBattlerTarget)
&& CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)
&& CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)
&& moveType == TYPE_FIRE)
{
gEffectBattler = gBattlerTarget;
@ -5870,11 +5870,12 @@ static enum ItemEffect HealConfuseBerry(u32 battler, u32 itemId, u32 flavorId, e
static enum ItemEffect StatRaiseBerry(u32 battler, u32 itemId, u32 statId, enum ItemCaseId caseID)
{
if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, itemId), itemId))
u32 ability = GetBattlerAbility(battler);
if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, ability) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, itemId), itemId))
{
BufferStatChange(battler, statId, STRINGID_STATROSE);
gEffectBattler = gBattleScripting.battler = battler;
if (GetBattlerAbility(battler) == ABILITY_RIPEN)
if (ability == ABILITY_RIPEN)
SET_STATCHANGER(statId, 2, FALSE);
else
SET_STATCHANGER(statId, 1, FALSE);
@ -5895,15 +5896,15 @@ static enum ItemEffect RandomStatRaiseBerry(u32 battler, u32 itemId, enum ItemCa
{
s32 stat;
enum StringID stringId;
u32 battlerAbility = GetBattlerAbility(battler);
for (stat = STAT_ATK; stat < NUM_STATS; stat++)
{
if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_LESS_THAN))
if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_LESS_THAN, battlerAbility))
break;
}
if (stat != NUM_STATS && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, itemId), itemId))
{
u16 battlerAbility = GetBattlerAbility(battler);
u32 savedAttacker = gBattlerAttacker;
// MoodyCantRaiseStat requires that the battler is set to gBattlerAttacker
gBattlerAttacker = gBattleScripting.battler = battler;
@ -5976,8 +5977,9 @@ static enum ItemEffect TrySetEnigmaBerry(u32 battler)
static enum ItemEffect DamagedStatBoostBerryEffect(u32 battler, u8 statId, enum DamageCategory category)
{
u32 ability = GetBattlerAbility(battler);
if (IsBattlerAlive(battler)
&& CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN)
&& CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, ability)
&& (gBattleScripting.overrideBerryRequirements
|| (!DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& GetBattleMoveCategory(gCurrentMove) == category
@ -5988,7 +5990,7 @@ static enum ItemEffect DamagedStatBoostBerryEffect(u32 battler, u8 statId, enum
BufferStatChange(battler, statId, STRINGID_STATROSE);
gEffectBattler = battler;
if (GetBattlerAbility(battler) == ABILITY_RIPEN)
if (ability == ABILITY_RIPEN)
SET_STATCHANGER(statId, 2, FALSE);
else
SET_STATCHANGER(statId, 1, FALSE);
@ -6004,7 +6006,7 @@ static enum ItemEffect DamagedStatBoostBerryEffect(u32 battler, u8 statId, enum
enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, u32 statId, u32 itemId, enum ItemCaseId caseID)
{
if (gFieldStatuses & terrainFlag && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN))
if (gFieldStatuses & terrainFlag && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battler)))
{
BufferStatChange(battler, statId, STRINGID_STATROSE);
gLastUsedItem = itemId; // For surge abilities
@ -6961,7 +6963,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
case HOLD_EFFECT_BLUNDER_POLICY:
if (gBattleStruct->blunderPolicy
&& IsBattlerAlive(gBattlerAttacker)
&& CompareStat(gBattlerAttacker, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
&& CompareStat(gBattlerAttacker, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerAttacker)))
{
gBattleStruct->blunderPolicy = FALSE;
gLastUsedItem = atkItem;
@ -10757,15 +10759,15 @@ bool32 TestIfSheerForceAffected(u32 battler, u16 move)
return GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && MoveIsAffectedBySheerForce(move);
}
// This function is the body of "jumpifstat", but can be used dynamically in a function
bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind)
// This function is the body of "jumpifstat", but can be used dynamically in a function. It considers Contrary.
bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind, u32 ability)
{
bool32 ret = FALSE;
u8 statValue = gBattleMons[battler].statStages[statId];
// Because this command is used as a way of checking if a stat can be lowered/raised,
// we need to do some modification at run-time.
if (GetBattlerAbility(battler) == ABILITY_CONTRARY)
if (ability == ABILITY_CONTRARY)
{
if (cmpKind == CMP_GREATER_THAN)
cmpKind = CMP_LESS_THAN;
@ -10836,7 +10838,7 @@ void BufferStatChange(u32 battler, u8 statId, enum StringID stringId)
bool32 TryRoomService(u32 battler)
{
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && CompareStat(battler, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN))
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && CompareStat(battler, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN, GetBattlerAbility(battler)))
{
BufferStatChange(battler, STAT_SPEED, STRINGID_STATFELL);
gEffectBattler = gBattleScripting.battler = battler;

View File

@ -128,7 +128,7 @@ static void SetUpItemUseCallback(u8 taskId)
type = gTasks[taskId].tEnigmaBerryType - 1;
else
type = GetItemType(gSpecialVar_ItemId) - 1;
if (gTasks[taskId].tUsingRegisteredKeyItem && type == (ITEM_USE_PARTY_MENU - 1))
{
FadeScreen(FADE_TO_BLACK, 0);
@ -1291,15 +1291,18 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon)
}
break;
case EFFECT_ITEM_INCREASE_ALL_STATS:
{
u32 ability = GetBattlerAbility(gBattlerInMenuId);
for (i = STAT_ATK; i < NUM_STATS; i++)
{
if (CompareStat(gBattlerInMenuId, i, MAX_STAT_STAGE, CMP_EQUAL))
if (CompareStat(gBattlerInMenuId, i, MAX_STAT_STAGE, CMP_EQUAL, ability))
{
cannotUse = TRUE;
break;
}
}
break;
}
case EFFECT_ITEM_RESTORE_HP:
if (hp == 0 || hp == GetMonData(mon, MON_DATA_MAX_HP))
cannotUse = TRUE;

View File

@ -159,7 +159,6 @@ SINGLE_BATTLE_TEST("Belly Drum maximizes the user's Attack stat, even when below
SINGLE_BATTLE_TEST("Belly Drum fails if the user's Attack is already at +6, even with Contrary")
{
KNOWN_FAILING;
GIVEN {
ASSUME(GetMoveEffect(MOVE_CHARM) == EFFECT_ATTACK_DOWN_2);
PLAYER(SPECIES_SERPERIOR) { Ability(ABILITY_CONTRARY); }
@ -190,7 +189,6 @@ SINGLE_BATTLE_TEST("Belly Drum fails if the user's Attack is already at +6, even
SINGLE_BATTLE_TEST("Belly Drum deducts HP if the user has Contrary and is at -6")
{
KNOWN_FAILING;
GIVEN {
ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2);
PLAYER(SPECIES_SERPERIOR) { Ability(ABILITY_CONTRARY); }
@ -215,6 +213,6 @@ SINGLE_BATTLE_TEST("Belly Drum deducts HP if the user has Contrary and is at -6"
ANIMATION(ANIM_TYPE_MOVE, MOVE_BELLY_DRUM, player);
s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP);
HP_BAR(player, hp: maxHP / 2);
MESSAGE("Wobbuffet cut its own HP and maximized its Attack!");
MESSAGE("Serperior cut its own HP and maximized its Attack!");
}
}