10/11/25 Master to upcoming merge

This commit is contained in:
AlexOn1ine 2025-11-01 11:54:17 +01:00
commit d4e7e7ad36
18 changed files with 271 additions and 117 deletions

View File

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

View File

@ -3685,7 +3685,7 @@ BattleScript_BlockedByPrimalWeatherRet::
BattleScript_EffectBellyDrum:: BattleScript_EffectBellyDrum::
attackcanceler attackcanceler
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 halvehp BattleScript_ButItFailed
attackanimation attackanimation
waitanimation waitanimation
@ -7440,11 +7440,13 @@ BattleScript_CuteCharmActivates::
return return
BattleScript_GooeyActivates:: BattleScript_GooeyActivates::
statbuffchange BS_ATTACKER, STAT_CHANGE_ONLY_CHECKING, BattleScript_GooeyActivatesRet
waitstate waitstate
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
swapattackerwithtarget @ for defiant, mirror armor swapattackerwithtarget @ for defiant, mirror armor
seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_SPD_MINUS_1 seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_SPD_MINUS_1
swapattackerwithtarget swapattackerwithtarget
BattleScript_GooeyActivatesRet:
return return
BattleScript_AbilityStatusEffect:: BattleScript_AbilityStatusEffect::

View File

@ -315,6 +315,7 @@ bool32 IsBattlerMegaEvolved(u32 battler);
bool32 IsBattlerPrimalReverted(u32 battler); bool32 IsBattlerPrimalReverted(u32 battler);
bool32 IsBattlerUltraBursted(u32 battler); bool32 IsBattlerUltraBursted(u32 battler);
u16 GetBattleFormChangeTargetSpecies(u32 battler, enum FormChanges method); u16 GetBattleFormChangeTargetSpecies(u32 battler, enum FormChanges method);
bool32 TryRevertPartyMonFormChange(u32 partyIndex);
bool32 TryBattleFormChange(u32 battler, enum FormChanges method); bool32 TryBattleFormChange(u32 battler, enum FormChanges method);
bool32 DoBattlersShareType(u32 battler1, u32 battler2); bool32 DoBattlersShareType(u32 battler1, u32 battler2);
bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId); bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId);
@ -346,7 +347,7 @@ void TrySaveExchangedItem(u32 battler, u16 stolenItem);
bool32 IsPartnerMonFromSameTrainer(u32 battler); bool32 IsPartnerMonFromSameTrainer(u32 battler);
bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes); bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes);
void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast); void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast);
bool32 CompareStat(u32 battler, enum Stat statId, u8 cmpTo, u8 cmpKind); bool32 CompareStat(u32 battler, enum Stat statId, u8 cmpTo, u8 cmpKind, enum Ability ability);
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget); bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget);
bool32 PickupHasValidTarget(u32 battler); bool32 PickupHasValidTarget(u32 battler);
bool32 CantPickupItem(u32 battler); bool32 CantPickupItem(u32 battler);

View File

@ -461,6 +461,7 @@ void HandleInputChooseTarget(u32 battler)
gBattleStruct->zmove.viewing = TRUE; gBattleStruct->zmove.viewing = TRUE;
ReloadMoveNames(battler); ReloadMoveNames(battler);
} }
TryToAddMoveInfoWindow();
DoBounceEffect(battler, BOUNCE_HEALTHBOX, 7, 1); DoBounceEffect(battler, BOUNCE_HEALTHBOX, 7, 1);
DoBounceEffect(battler, BOUNCE_MON, 7, 1); DoBounceEffect(battler, BOUNCE_MON, 7, 1);
EndBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX); EndBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX);

View File

@ -77,7 +77,7 @@ enum ItemEffect TryBoosterEnergy(u32 battler, enum Ability ability, ActivationTi
static enum ItemEffect TryRoomService(u32 battler, ActivationTiming timing) static enum ItemEffect TryRoomService(u32 battler, ActivationTiming timing)
{ {
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)))
{ {
gEffectBattler = gBattleScripting.battler = battler; gEffectBattler = gBattleScripting.battler = battler;
SET_STATCHANGER(STAT_SPEED, 1, TRUE); SET_STATCHANGER(STAT_SPEED, 1, TRUE);
@ -97,7 +97,7 @@ static enum ItemEffect TryRoomService(u32 battler, ActivationTiming timing)
enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, enum Stat statId, ActivationTiming timing) enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, enum Stat statId, ActivationTiming timing)
{ {
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)))
{ {
gEffectBattler = gBattleScripting.battler = battler; gEffectBattler = gBattleScripting.battler = battler;
SET_STATCHANGER(statId, 1, FALSE); SET_STATCHANGER(statId, 1, FALSE);
@ -423,7 +423,7 @@ static enum ItemEffect TryBlunderPolicy(u32 battlerAtk)
if (gBattleStruct->blunderPolicy if (gBattleStruct->blunderPolicy
&& IsBattlerAlive(battlerAtk) && IsBattlerAlive(battlerAtk)
&& CompareStat(battlerAtk, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) && CompareStat(battlerAtk, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battlerAtk)))
{ {
gBattleStruct->blunderPolicy = FALSE; gBattleStruct->blunderPolicy = FALSE;
SET_STATCHANGER(STAT_SPEED, 2, FALSE); SET_STATCHANGER(STAT_SPEED, 2, FALSE);
@ -502,7 +502,7 @@ static enum ItemEffect TryThroatSpray(u32 battlerAtk)
&& gMultiHitCounter == 0 && gMultiHitCounter == 0
&& IsBattlerAlive(battlerAtk) && IsBattlerAlive(battlerAtk)
&& IsAnyTargetTurnDamaged(battlerAtk) && IsAnyTargetTurnDamaged(battlerAtk)
&& CompareStat(battlerAtk, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN) && CompareStat(battlerAtk, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battlerAtk))
&& !NoAliveMonsForEitherParty()) // Don't activate if battle will end && !NoAliveMonsForEitherParty()) // Don't activate if battle will end
{ {
SET_STATCHANGER(STAT_SPATK, 1, FALSE); SET_STATCHANGER(STAT_SPATK, 1, FALSE);
@ -517,7 +517,7 @@ static enum ItemEffect DamagedStatBoostBerryEffect(u32 battlerDef, u32 battlerAt
{ {
enum ItemEffect effect = ITEM_NO_EFFECT; enum ItemEffect effect = ITEM_NO_EFFECT;
if (!IsBattlerAlive(battlerDef) || !CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN)) if (!IsBattlerAlive(battlerDef) || !CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battlerDef)))
return effect; return effect;
if (gBattleScripting.overrideBerryRequirements if (gBattleScripting.overrideBerryRequirements
@ -970,7 +970,7 @@ static enum ItemEffect StatRaiseBerry(u32 battler, u32 itemId, enum Stat statId,
enum ItemEffect effect = ITEM_NO_EFFECT; enum ItemEffect effect = ITEM_NO_EFFECT;
enum Ability ability = GetBattlerAbility(battler); enum Ability ability = GetBattlerAbility(battler);
if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN) if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, ability)
&& HasEnoughHpToEatBerry(battler, ability, GetItemHoldEffectParam(itemId), itemId)) && HasEnoughHpToEatBerry(battler, ability, GetItemHoldEffectParam(itemId), itemId))
{ {
gEffectBattler = gBattleScripting.battler = battler; gEffectBattler = gBattleScripting.battler = battler;
@ -1011,17 +1011,17 @@ static enum ItemEffect RandomStatRaiseBerry(u32 battler, u32 itemId, ActivationT
{ {
enum ItemEffect effect = ITEM_NO_EFFECT; enum ItemEffect effect = ITEM_NO_EFFECT;
enum Stat stat; enum Stat stat;
enum Ability ability = GetBattlerAbility(battler);
for (stat = STAT_ATK; stat < NUM_STATS; stat++) 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, ability))
break; break;
} }
if (stat == NUM_STATS) if (stat == NUM_STATS)
return effect; return effect;
enum Ability ability = GetBattlerAbility(battler);
if (HasEnoughHpToEatBerry(battler, ability, GetItemHoldEffectParam(itemId), itemId)) if (HasEnoughHpToEatBerry(battler, ability, GetItemHoldEffectParam(itemId), itemId))
{ {
u32 savedAttacker = gBattlerAttacker; u32 savedAttacker = gBattlerAttacker;

View File

@ -5642,18 +5642,7 @@ static void HandleEndTurn_FinishBattle(void)
for (i = 0; i < PARTY_SIZE; i++) for (i = 0; i < PARTY_SIZE; i++)
{ {
bool8 changedForm = FALSE; bool32 changedForm = TryRevertPartyMonFormChange(i);
// Appeared in battle and didn't faint
if (gBattleStruct->partyState[B_SIDE_PLAYER][i].sentOut && GetMonData(&gPlayerParty[i], MON_DATA_HP, NULL) != 0)
changedForm = TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE_ENVIRONMENT);
if (!changedForm)
changedForm = TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE);
// Clear original species field
gBattleStruct->partyState[B_SIDE_PLAYER][i].changedSpecies = SPECIES_NONE;
gBattleStruct->partyState[B_SIDE_OPPONENT][i].changedSpecies = SPECIES_NONE;
// Recalculate the stats of every party member before the end // Recalculate the stats of every party member before the end
if (!changedForm && B_RECALCULATE_STATS >= GEN_5) if (!changedForm && B_RECALCULATE_STATS >= GEN_5)

View File

@ -370,7 +370,7 @@ static void Cmd_jumpifvolatile(void);
static void Cmd_jumpifability(void); static void Cmd_jumpifability(void);
static void Cmd_jumpifsideaffecting(void); static void Cmd_jumpifsideaffecting(void);
static void Cmd_jumpifstat(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_jumpbasedontype(void);
static void Cmd_getexp(void); static void Cmd_getexp(void);
static void Cmd_checkteamslost(void); static void Cmd_checkteamslost(void);
@ -629,7 +629,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
Cmd_jumpifability, //0x1E Cmd_jumpifability, //0x1E
Cmd_jumpifsideaffecting, //0x1F Cmd_jumpifsideaffecting, //0x1F
Cmd_jumpifstat, //0x20 Cmd_jumpifstat, //0x20
Cmd_unused_0x21, //0x21 Cmd_jumpifstatignorecontrary, //0x21
Cmd_jumpbasedontype, //0x22 Cmd_jumpbasedontype, //0x22
Cmd_getexp, //0x23 Cmd_getexp, //0x23
Cmd_checkteamslost, //0x24 Cmd_checkteamslost, //0x24
@ -4384,7 +4384,7 @@ static void Cmd_jumpifstat(void)
u8 value = cmd->value; u8 value = cmd->value;
u8 comparison = cmd->comparison; u8 comparison = cmd->comparison;
ret = CompareStat(battler, stat, value, comparison); ret = CompareStat(battler, stat, value, comparison, GetBattlerAbility(battler));
if (ret) if (ret)
gBattlescriptCurrInstr = cmd->jumpInstr; gBattlescriptCurrInstr = cmd->jumpInstr;
@ -4392,8 +4392,22 @@ static void Cmd_jumpifstat(void)
gBattlescriptCurrInstr = cmd->nextInstr; 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) static void Cmd_jumpbasedontype(void)
@ -5572,7 +5586,7 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move
else if (abilityAtk == ABILITY_GRIM_NEIGH || abilityAtk == ABILITY_AS_ONE_SHADOW_RIDER) else if (abilityAtk == ABILITY_GRIM_NEIGH || abilityAtk == ABILITY_AS_ONE_SHADOW_RIDER)
stat = STAT_SPATK; 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; gLastUsedAbility = abilityAtk;
if (abilityAtk == ABILITY_AS_ONE_ICE_RIDER) if (abilityAtk == ABILITY_AS_ONE_ICE_RIDER)
@ -5612,17 +5626,17 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move
else else
{ {
u32 numStatBuffs = 0; 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; gBattleScripting.animArg1 = GET_STAT_BUFF_ID(STAT_ATK) + STAT_ANIM_PLUS1;
numStatBuffs++; 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; gBattleScripting.animArg1 = GET_STAT_BUFF_ID(STAT_SPATK) + STAT_ANIM_PLUS1;
numStatBuffs++; 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; gBattleScripting.animArg1 = GET_STAT_BUFF_ID(STAT_SPEED) + STAT_ANIM_PLUS1;
numStatBuffs++; numStatBuffs++;
@ -5853,7 +5867,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
&& !IsBattlerAlive(gBattlerTarget) && !IsBattlerAlive(gBattlerTarget)
&& IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget)
&& !NoAliveMonsForEitherParty() && !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); SET_STATCHANGER(STAT_ATK, GetGenConfig(GEN_CONFIG_FELL_STINGER_STAT_RAISE) >= GEN_7 ? 3 : 2, FALSE);
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK); PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK);
@ -6118,7 +6132,7 @@ static void Cmd_moveend(void)
&& !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget)
&& IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget)
&& !IsBattleMoveStatus(gCurrentMove) && !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); SET_STATCHANGER(STAT_ATK, 1, FALSE);
BattleScriptCall(BattleScript_RageIsBuilding); BattleScriptCall(BattleScript_RageIsBuilding);
@ -11912,7 +11926,7 @@ static void Cmd_jumpifconfusedandstatmaxed(void)
CMD_ARGS(u8 stat, const u8 *jumpInstr); CMD_ARGS(u8 stat, const u8 *jumpInstr);
if (gBattleMons[gBattlerTarget].volatiles.confusionTurns > 0 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 gBattlescriptCurrInstr = cmd->jumpInstr; // Fails if we're confused AND stat cannot be raised
else else
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
@ -13892,6 +13906,8 @@ static void Cmd_givecaughtmon(void)
} }
else else
{ {
//Before sending to PC, we revert battle form
TryRevertPartyMonFormChange(gSelectedMonPartyId);
// Mon chosen, try to put it in the PC // Mon chosen, try to put it in the PC
if (CopyMonToPC(&gPlayerParty[gSelectedMonPartyId]) == MON_GIVEN_TO_PC) if (CopyMonToPC(&gPlayerParty[gSelectedMonPartyId]) == MON_GIVEN_TO_PC)
{ {
@ -15690,7 +15706,7 @@ void BS_CanTarShotWork(void)
NATIVE_ARGS(const u8 *failInstr); 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 // 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 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; gBattlescriptCurrInstr = cmd->nextInstr;
else else
gBattlescriptCurrInstr = cmd->failInstr; gBattlescriptCurrInstr = cmd->failInstr;
@ -16705,7 +16721,7 @@ void BS_TryAcupressure(void)
u32 bits = 0; u32 bits = 0;
for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) for (enum Stat 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; bits |= 1u << stat;
} }
if (bits) if (bits)
@ -17104,10 +17120,11 @@ void BS_TryActivateSoulheart(void)
while (gBattleStruct->soulheartBattlerId < gBattlersCount) while (gBattleStruct->soulheartBattlerId < gBattlersCount)
{ {
gBattleScripting.battler = gBattleStruct->soulheartBattlerId++; gBattleScripting.battler = gBattleStruct->soulheartBattlerId++;
if (GetBattlerAbility(gBattleScripting.battler) == ABILITY_SOUL_HEART u32 ability = GetBattlerAbility(gBattleScripting.battler);
if (ability == ABILITY_SOUL_HEART
&& IsBattlerAlive(gBattleScripting.battler) && IsBattlerAlive(gBattleScripting.battler)
&& !NoAliveMonsForEitherParty() && !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); SET_STATCHANGER(STAT_SPATK, 1, FALSE);
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPATK); PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPATK);
@ -17922,11 +17939,12 @@ void BS_SetAttackerToStickyWebUser(void)
void BS_CutOneThirdHpAndRaiseStats(void) void BS_CutOneThirdHpAndRaiseStats(void)
{ {
NATIVE_ARGS(const u8 *failInstr); NATIVE_ARGS(const u8 *failInstr);
bool32 atLeastOneStatBoosted = FALSE; bool32 atLeastOneStatBoosted = FALSE;
u32 ability = GetBattlerAbility(gBattlerAttacker);
for (u32 stat = 1; stat < NUM_STATS; stat++) 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; atLeastOneStatBoosted = TRUE;
break; break;

View File

@ -66,6 +66,7 @@ static u32 GetFlingPowerFromItemId(u32 itemId);
static void SetRandomMultiHitCounter(); static void SetRandomMultiHitCounter();
static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, enum Ability abilityDef, enum Ability abilityAffected, const u8 *battleScript, enum FunctionCallOption option); static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, enum Ability abilityDef, enum Ability abilityAffected, const u8 *battleScript, enum FunctionCallOption option);
static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum FunctionCallOption option); static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum FunctionCallOption option);
static bool32 IsOpposingSideEmpty(u32 battler);
// Submoves // Submoves
static u32 GetMirrorMoveMove(void); static u32 GetMirrorMoveMove(void);
@ -1237,7 +1238,7 @@ void PrepareStringBattle(enum StringID stringId, u32 battler)
case STRINGID_PKMNCUTSATTACKWITH: case STRINGID_PKMNCUTSATTACKWITH:
if (GetGenConfig(GEN_CONFIG_UPDATED_INTIMIDATE) >= GEN_8 if (GetGenConfig(GEN_CONFIG_UPDATED_INTIMIDATE) >= GEN_8
&& targetAbility == ABILITY_RATTLED && 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; gBattlerAbility = gBattlerTarget;
BattleScriptCall(BattleScript_AbilityRaisesDefenderStat); BattleScriptCall(BattleScript_AbilityRaisesDefenderStat);
@ -1763,13 +1764,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 // 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) 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 // 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) 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) void TryToRevertMimicryAndFlags(void)
@ -3540,7 +3541,7 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability ability
break; break;
case MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY: case MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY:
gBattleStruct->pledgeMove = FALSE; gBattleStruct->pledgeMove = FALSE;
if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN)) if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, abilityDef))
{ {
battleScript = BattleScript_MonMadeMoveUseless; battleScript = BattleScript_MonMadeMoveUseless;
} }
@ -4119,7 +4120,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
gSpecialStatuses[battler].switchInAbilityDone = TRUE; 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); SET_STATCHANGER(statId, 1, FALSE);
SaveBattlerAttacker(gBattlerAttacker); SaveBattlerAttacker(gBattlerAttacker);
@ -4272,7 +4273,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
} }
break; break;
case ABILITY_INTIMIDATE: case ABILITY_INTIMIDATE:
if (!gSpecialStatuses[battler].switchInAbilityDone) if (!gSpecialStatuses[battler].switchInAbilityDone && !IsOpposingSideEmpty(battler))
{ {
SaveBattlerAttacker(gBattlerAttacker); SaveBattlerAttacker(gBattlerAttacker);
gBattlerAttacker = battler; gBattlerAttacker = battler;
@ -4284,7 +4285,8 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
break; break;
case ABILITY_SUPERSWEET_SYRUP: case ABILITY_SUPERSWEET_SYRUP:
if (!gSpecialStatuses[battler].switchInAbilityDone if (!gSpecialStatuses[battler].switchInAbilityDone
&& !GetBattlerPartyState(battler)->supersweetSyrup) && !GetBattlerPartyState(battler)->supersweetSyrup
&& !IsOpposingSideEmpty(battler))
{ {
SaveBattlerAttacker(gBattlerAttacker); SaveBattlerAttacker(gBattlerAttacker);
gBattlerAttacker = battler; gBattlerAttacker = battler;
@ -4331,7 +4333,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (GetGenConfig(GEN_INTREPID_SWORD) == GEN_9) if (GetGenConfig(GEN_INTREPID_SWORD) == GEN_9)
GetBattlerPartyState(battler)->intrepidSwordBoost = TRUE; GetBattlerPartyState(battler)->intrepidSwordBoost = TRUE;
gSpecialStatuses[battler].switchInAbilityDone = 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); SET_STATCHANGER(STAT_ATK, 1, FALSE);
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn); BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
@ -4346,7 +4348,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (GetGenConfig(GEN_DAUNTLESS_SHIELD) == GEN_9) if (GetGenConfig(GEN_DAUNTLESS_SHIELD) == GEN_9)
GetBattlerPartyState(battler)->dauntlessShieldBoost = TRUE; GetBattlerPartyState(battler)->dauntlessShieldBoost = TRUE;
gSpecialStatuses[battler].switchInAbilityDone = 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); SET_STATCHANGER(STAT_DEF, 1, FALSE);
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn); BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
@ -4356,7 +4358,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
break; break;
case ABILITY_WIND_RIDER: case ABILITY_WIND_RIDER:
if (!gSpecialStatuses[battler].switchInAbilityDone 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) && gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TAILWIND)
{ {
gSpecialStatuses[battler].switchInAbilityDone = TRUE; gSpecialStatuses[battler].switchInAbilityDone = TRUE;
@ -4496,7 +4498,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
else //ABILITY_EMBODY_ASPECT_TEAL_MASK else //ABILITY_EMBODY_ASPECT_TEAL_MASK
stat = STAT_SPEED; stat = STAT_SPEED;
if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_EQUAL)) if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_EQUAL, gLastUsedAbility))
break; break;
gSpecialStatuses[battler].switchInAbilityDone = TRUE; gSpecialStatuses[battler].switchInAbilityDone = TRUE;
@ -4646,7 +4648,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
} }
break; break;
case ABILITY_SPEED_BOOST: 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)
{ {
SaveBattlerAttacker(gBattlerAttacker); SaveBattlerAttacker(gBattlerAttacker);
SET_STATCHANGER(STAT_SPEED, 1, FALSE); SET_STATCHANGER(STAT_SPEED, 1, FALSE);
@ -4663,9 +4665,9 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
for (i = STAT_ATK; i < statsNum; i++) 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; 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; validToRaise |= 1u << i;
} }
@ -4807,7 +4809,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (IsBattlerTurnDamaged(battler) if (IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& HadMoreThanHalfHpNowDoesnt(battler) && HadMoreThanHalfHpNowDoesnt(battler)
&& CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)) && CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{ {
gEffectBattler = gBattlerAbility = battler; gEffectBattler = gBattlerAbility = battler;
SET_STATCHANGER(STAT_SPATK, 1, FALSE); SET_STATCHANGER(STAT_SPATK, 1, FALSE);
@ -4836,7 +4838,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (IsBattlerTurnDamaged(battler) if (IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& moveType == TYPE_DARK && 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 = gBattlerAbility = battler; gEffectBattler = gBattlerAbility = battler;
SET_STATCHANGER(STAT_ATK, 1, FALSE); SET_STATCHANGER(STAT_ATK, 1, FALSE);
@ -4848,7 +4850,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (IsBattlerTurnDamaged(battler) if (IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& (moveType == TYPE_DARK || moveType == TYPE_BUG || moveType == TYPE_GHOST) && (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 = gBattlerAbility = battler; gEffectBattler = gBattlerAbility = battler;
SET_STATCHANGER(STAT_SPEED, 1, FALSE); SET_STATCHANGER(STAT_SPEED, 1, FALSE);
@ -4860,7 +4862,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (IsBattlerTurnDamaged(battler) if (IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& moveType == TYPE_WATER && 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 = gBattlerAbility = battler; gEffectBattler = gBattlerAbility = battler;
SET_STATCHANGER(STAT_DEF, 2, FALSE); SET_STATCHANGER(STAT_DEF, 2, FALSE);
@ -4872,7 +4874,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (gBattlerAttacker != gBattlerTarget if (gBattlerAttacker != gBattlerTarget
&& IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN)) && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
{ {
gEffectBattler = gBattlerAbility = battler; gEffectBattler = gBattlerAbility = battler;
SET_STATCHANGER(STAT_DEF, 1, FALSE); SET_STATCHANGER(STAT_DEF, 1, FALSE);
@ -4884,8 +4886,8 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (IsBattlerTurnDamaged(battler) if (IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& IsBattleMovePhysical(gCurrentMove) && 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_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))) || CompareStat(battler, STAT_DEF, MIN_STAT_STAGE, CMP_GREATER_THAN, gLastUsedAbility)))
{ {
if (GetMoveEffect(gCurrentMove) == EFFECT_HIT_ESCAPE && CanBattlerSwitch(gBattlerAttacker)) if (GetMoveEffect(gCurrentMove) == EFFECT_HIT_ESCAPE && CanBattlerSwitch(gBattlerAttacker))
gProtectStructs[battler].disableEjectPack = TRUE; // Set flag for target gProtectStructs[battler].disableEjectPack = TRUE; // Set flag for target
@ -4964,7 +4966,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (gSpecialStatuses[battler].criticalHit if (gSpecialStatuses[battler].criticalHit
&& IsBattlerTurnDamaged(battler) && IsBattlerTurnDamaged(battler)
&& IsBattlerAlive(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); SET_STATCHANGER(STAT_ATK, MAX_STAT_STAGE - gBattleMons[battler].statStages[STAT_ATK], FALSE);
BattleScriptCall(BattleScript_TargetsStatWasMaxedOut); BattleScriptCall(BattleScript_TargetsStatWasMaxedOut);
@ -4974,7 +4976,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
case ABILITY_GOOEY: case ABILITY_GOOEY:
case ABILITY_TANGLING_HAIR: case ABILITY_TANGLING_HAIR:
if (IsBattlerAlive(gBattlerAttacker) 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 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget)
&& !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)) && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move))
@ -5178,7 +5180,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
case ABILITY_STEAM_ENGINE: case ABILITY_STEAM_ENGINE:
if (IsBattlerTurnDamaged(gBattlerTarget) if (IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(battler) && 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)) && (moveType == TYPE_FIRE || moveType == TYPE_WATER))
{ {
gEffectBattler = gBattlerAbility = battler; gEffectBattler = gBattlerAbility = battler;
@ -5260,7 +5262,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
case ABILITY_THERMAL_EXCHANGE: case ABILITY_THERMAL_EXCHANGE:
if (IsBattlerTurnDamaged(gBattlerTarget) if (IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(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) && moveType == TYPE_FIRE)
{ {
gEffectBattler = gBattlerAbility = gBattlerTarget; gEffectBattler = gBattlerAbility = gBattlerTarget;
@ -9052,17 +9054,46 @@ bool32 CanBattlerFormChange(u32 battler, enum FormChanges method)
if (gBattleMons[battler].volatiles.transformed if (gBattleMons[battler].volatiles.transformed
&& B_TRANSFORM_FORM_CHANGES >= GEN_5) && B_TRANSFORM_FORM_CHANGES >= GEN_5)
return FALSE; return FALSE;
// Mega Evolved and Ultra Bursted Pokémon should always revert to normal upon fainting or ending the battle.
if ((IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE)) switch (method)
{
case FORM_CHANGE_END_BATTLE:
if (IsBattlerPrimalReverted(battler))
return TRUE; return TRUE;
else if (IsBattlerPrimalReverted(battler) && (method == FORM_CHANGE_END_BATTLE)) // Fallthrough
case FORM_CHANGE_FAINT:
if (IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler) || IsGigantamaxed(battler))
return TRUE; return TRUE;
// Gigantamaxed Pokemon should revert upon fainting, switching, or ending the battle. break;
else if (IsGigantamaxed(battler) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_BATTLE_SWITCH || method == FORM_CHANGE_END_BATTLE)) case FORM_CHANGE_BATTLE_SWITCH:
if (IsGigantamaxed(battler))
return TRUE; return TRUE;
else if (GetActiveGimmick(battler) == GIMMICK_TERA && GetBattlerAbility(battler) == ABILITY_HUNGER_SWITCH)
return FALSE;
break;
default:
break;
}
return DoesSpeciesHaveFormChangeMethod(gBattleMons[battler].species, method); return DoesSpeciesHaveFormChangeMethod(gBattleMons[battler].species, method);
} }
bool32 TryRevertPartyMonFormChange(u32 partyIndex)
{
bool32 changedForm = FALSE;
// Appeared in battle and didn't faint
if (gBattleStruct->partyState[B_SIDE_PLAYER][partyIndex].sentOut && GetMonData(&gPlayerParty[partyIndex], MON_DATA_HP, NULL) != 0)
changedForm = TryFormChange(partyIndex, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE_ENVIRONMENT);
if (!changedForm)
changedForm = TryFormChange(partyIndex, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE);
// Clear original species field
gBattleStruct->partyState[B_SIDE_PLAYER][partyIndex].changedSpecies = SPECIES_NONE;
return changedForm;
}
bool32 TryBattleFormChange(u32 battler, enum FormChanges method) bool32 TryBattleFormChange(u32 battler, enum FormChanges method)
{ {
u32 monId = gBattlerPartyIndexes[battler]; u32 monId = gBattlerPartyIndexes[battler];
@ -9076,7 +9107,7 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method)
targetSpecies = GetBattleFormChangeTargetSpecies(battler, method); targetSpecies = GetBattleFormChangeTargetSpecies(battler, method);
if (targetSpecies == currentSpecies) if (targetSpecies == currentSpecies)
targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0); targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0);
if (targetSpecies != currentSpecies) if (targetSpecies != currentSpecies && targetSpecies != SPECIES_NONE)
{ {
// Saves the original species on the first form change. // Saves the original species on the first form change.
@ -9093,17 +9124,22 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method)
{ {
bool32 restoreSpecies = FALSE; bool32 restoreSpecies = FALSE;
// Mega Evolved and Ultra Bursted Pokémon should always revert to normal upon fainting or ending the battle, so no need to add it to the form change tables. switch (method)
if ((IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE)) {
case FORM_CHANGE_END_BATTLE:
restoreSpecies = TRUE; restoreSpecies = TRUE;
break;
// Unlike Megas, Primal Reversion isn't canceled on fainting. case FORM_CHANGE_FAINT:
else if (IsBattlerPrimalReverted(battler) && (method == FORM_CHANGE_END_BATTLE)) if (IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler) || IsGigantamaxed(battler))
restoreSpecies = TRUE; restoreSpecies = TRUE;
break;
// Gigantamax Pokemon have their forms reverted after fainting, switching, or ending the battle. case FORM_CHANGE_BATTLE_SWITCH:
else if (IsGigantamaxed(battler) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_BATTLE_SWITCH || method == FORM_CHANGE_END_BATTLE)) if (IsGigantamaxed(battler))
restoreSpecies = TRUE; restoreSpecies = TRUE;
break;
default:
break;
}
if (restoreSpecies) if (restoreSpecies)
{ {
@ -9674,14 +9710,14 @@ bool32 TestIfSheerForceAffected(u32 battler, u16 move)
} }
// This function is the body of "jumpifstat", but can be used dynamically in a function // This function is the body of "jumpifstat", but can be used dynamically in a function
bool32 CompareStat(u32 battler, enum Stat statId, u8 cmpTo, u8 cmpKind) bool32 CompareStat(u32 battler, enum Stat statId, u8 cmpTo, u8 cmpKind, enum Ability ability)
{ {
bool32 ret = FALSE; bool32 ret = FALSE;
u8 statValue = gBattleMons[battler].statStages[statId]; u8 statValue = gBattleMons[battler].statStages[statId];
// Because this command is used as a way of checking if a stat can be lowered/raised, // 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. // we need to do some modification at run-time.
if (GetBattlerAbility(battler) == ABILITY_CONTRARY) if (ability == ABILITY_CONTRARY)
{ {
if (cmpKind == CMP_GREATER_THAN) if (cmpKind == CMP_GREATER_THAN)
cmpKind = CMP_LESS_THAN; cmpKind = CMP_LESS_THAN;
@ -10772,6 +10808,21 @@ bool32 HasPartnerTrainer(u32 battler)
return FALSE; return FALSE;
} }
static bool32 IsOpposingSideEmpty(u32 battler)
{
u32 oppositeBattler = BATTLE_OPPOSITE(battler);
if (IsBattlerAlive(oppositeBattler))
return FALSE;
if (!IsDoubleBattle())
return TRUE;
if (IsBattlerAlive(BATTLE_PARTNER(oppositeBattler)))
return FALSE;
return TRUE;
}
static u32 GetMirrorMoveMove(void) static u32 GetMirrorMoveMove(void)
{ {
s32 i, validMovesCount; s32 i, validMovesCount;

View File

@ -1306,15 +1306,18 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon)
} }
break; break;
case EFFECT_ITEM_INCREASE_ALL_STATS: case EFFECT_ITEM_INCREASE_ALL_STATS:
{
u32 ability = GetBattlerAbility(gBattlerInMenuId);
for (i = STAT_ATK; i < NUM_STATS; i++) 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; cannotUse = TRUE;
break; break;
} }
} }
break; break;
}
case EFFECT_ITEM_RESTORE_HP: case EFFECT_ITEM_RESTORE_HP:
if (hp == 0 || hp == GetMonData(mon, MON_DATA_MAX_HP)) if (hp == 0 || hp == GetMonData(mon, MON_DATA_MAX_HP))
cannotUse = TRUE; cannotUse = TRUE;

View File

@ -1511,7 +1511,7 @@ static void HandleChooseMonSelection(u8 taskId, s8 *slotPtr)
} }
case PARTY_ACTION_SEND_MON_TO_BOX: case PARTY_ACTION_SEND_MON_TO_BOX:
{ {
u8 partyId = GetPartyIdFromBattleSlot((u8)*slotPtr); u8 partyId = (u8)*slotPtr;
if (partyId == 0 || ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && partyId == 1)) if (partyId == 0 || ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && partyId == 1))
{ {
// Can't select if mon is currently on the field // Can't select if mon is currently on the field
@ -1538,7 +1538,7 @@ static void HandleChooseMonSelection(u8 taskId, s8 *slotPtr)
else else
{ {
PlaySE(SE_SELECT); PlaySE(SE_SELECT);
gSelectedMonPartyId = partyId; gSelectedMonPartyId = GetPartyIdFromBattleSlot(partyId);
Task_ClosePartyMenu(taskId); Task_ClosePartyMenu(taskId);
} }
break; break;

View File

@ -399,6 +399,7 @@ bool8 CheckForTrainersWantingBattle(void)
if (numTrainers == 0xFF) // non-trainerbattle script if (numTrainers == 0xFF) // non-trainerbattle script
{ {
u32 objectEventId = gApproachingTrainers[gNoOfApproachingTrainers - 1].objectEventId; u32 objectEventId = gApproachingTrainers[gNoOfApproachingTrainers - 1].objectEventId;
gApproachingTrainers[gNoOfApproachingTrainers - 1].trainerScriptPtr = GetObjectEventScriptPointerByObjectEventId(objectEventId);
gSelectedObjectEvent = objectEventId; gSelectedObjectEvent = objectEventId;
gSpecialVar_LastTalked = gObjectEvents[objectEventId].localId; gSpecialVar_LastTalked = gObjectEvents[objectEventId].localId;
ScriptContext_SetupScript(EventScript_ObjectApproachPlayer); ScriptContext_SetupScript(EventScript_ObjectApproachPlayer);

View File

@ -53,7 +53,6 @@ SINGLE_BATTLE_TEST("Hunger Switch does not switch Morpeko's form when Terastalli
SINGLE_BATTLE_TEST("Hunger Switch does not switch Morpeko's form after switching out while Terastallized") SINGLE_BATTLE_TEST("Hunger Switch does not switch Morpeko's form after switching out while Terastallized")
{ {
KNOWN_FAILING; // #7062
GIVEN { GIVEN {
ASSUME(GetMoveEffect(MOVE_ROAR) == EFFECT_ROAR); ASSUME(GetMoveEffect(MOVE_ROAR) == EFFECT_ROAR);
PLAYER(SPECIES_MORPEKO) { Ability(ABILITY_HUNGER_SWITCH); TeraType(TYPE_NORMAL); } PLAYER(SPECIES_MORPEKO) { Ability(ABILITY_HUNGER_SWITCH); TeraType(TYPE_NORMAL); }

View File

@ -240,6 +240,7 @@ DOUBLE_BATTLE_TEST("Intimidate is not going to trigger if a mon switches out thr
ANIMATION(ANIM_TYPE_MOVE, MOVE_HEALING_WISH, opponentRight); ANIMATION(ANIM_TYPE_MOVE, MOVE_HEALING_WISH, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, playerLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, playerLeft);
HP_BAR(opponentLeft); HP_BAR(opponentLeft);
NOT ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
MESSAGE("2 sent out Treecko!"); MESSAGE("2 sent out Treecko!");
MESSAGE("2 sent out Torchic!"); MESSAGE("2 sent out Torchic!");
NOT ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE); NOT ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
@ -264,7 +265,7 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutral
} }
} }
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - switching moves") DOUBLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - switching moves")
{ {
u32 move; u32 move;
PARAMETRIZE { move = MOVE_U_TURN; } PARAMETRIZE { move = MOVE_U_TURN; }
@ -276,19 +277,24 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutral
ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS);
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); } PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
PLAYER(SPECIES_WOBBUFFET) { HP(1); } PLAYER(SPECIES_WOBBUFFET) { HP(1); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN { } WHEN {
TURN { MOVE(player, move); SEND_OUT(player, 1); } TURN {
if (move == MOVE_U_TURN)
MOVE(playerLeft, move, target: opponentLeft);
else
MOVE(playerLeft, move);
SEND_OUT(playerLeft, 2);
}
} SCENE { } SCENE {
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS); ABILITY_POPUP(playerLeft, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing gas filled the area!"); MESSAGE("Neutralizing gas filled the area!");
ANIMATION(ANIM_TYPE_MOVE, move, player); ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
MESSAGE("The effects of the neutralizing gas wore off!"); MESSAGE("The effects of the neutralizing gas wore off!");
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE);
SEND_IN_MESSAGE("Wobbuffet"); SEND_IN_MESSAGE("Wobbuffet");
} THEN {
if (move == MOVE_HEALING_WISH)
EXPECT_EQ(player->hp, player->maxHP);
} }
} }
@ -330,23 +336,25 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutral
} }
} }
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - fainted") DOUBLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - fainted")
{ {
GIVEN { GIVEN {
ASSUME(GetMoveEffect(MOVE_FELL_STINGER) == EFFECT_FELL_STINGER); ASSUME(GetMoveEffect(MOVE_FELL_STINGER) == EFFECT_FELL_STINGER);
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); } PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); }
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN { } WHEN {
TURN { MOVE(opponent, MOVE_FELL_STINGER); SEND_OUT(player, 1); } TURN { MOVE(opponentLeft, MOVE_FELL_STINGER, target: playerLeft); SEND_OUT(playerLeft, 2); }
} SCENE { } SCENE {
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS); ABILITY_POPUP(playerLeft, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing gas filled the area!"); MESSAGE("Neutralizing gas filled the area!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FELL_STINGER, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_FELL_STINGER, opponentLeft);
MESSAGE("The effects of the neutralizing gas wore off!"); MESSAGE("The effects of the neutralizing gas wore off!");
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE);
MESSAGE("Weezing fainted!"); MESSAGE("Weezing fainted!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
SEND_IN_MESSAGE("Wobbuffet"); SEND_IN_MESSAGE("Wobbuffet");
} }
} }

View File

@ -2,3 +2,56 @@
#include "test/battle.h" #include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Power Construct (Ability) test titles") TO_DO_BATTLE_TEST("TODO: Write Power Construct (Ability) test titles")
SINGLE_BATTLE_TEST("Power Construct switches Zygarde's form when HP is below half")
{
u16 baseSpecies;
PARAMETRIZE { baseSpecies = SPECIES_ZYGARDE_10_POWER_CONSTRUCT; }
PARAMETRIZE { baseSpecies = SPECIES_ZYGARDE_50_POWER_CONSTRUCT; }
GIVEN {
PLAYER(baseSpecies)
{
Ability(ABILITY_POWER_CONSTRUCT);
HP((GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP) / 2) + 1);
}
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SCRATCH); MOVE(player, MOVE_CELEBRATE); }
} SCENE {
MESSAGE("You sense the presence of many!");
ABILITY_POPUP(player, ABILITY_POWER_CONSTRUCT);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_POWER_CONSTRUCT, player);
} THEN {
EXPECT_EQ(player->species, SPECIES_ZYGARDE_COMPLETE);
}
}
WILD_BATTLE_TEST("Power Construct Zygarde reverts to its original form upon catching")
{
u16 baseSpecies;
PARAMETRIZE { baseSpecies = SPECIES_ZYGARDE_10_POWER_CONSTRUCT; }
PARAMETRIZE { baseSpecies = SPECIES_ZYGARDE_50_POWER_CONSTRUCT; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(baseSpecies)
{
Ability(ABILITY_POWER_CONSTRUCT);
HP((GetMonData(&OPPONENT_PARTY[0], MON_DATA_MAX_HP) / 2) + 1);
}
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
TURN { USE_ITEM(player, ITEM_MASTER_BALL); }
} SCENE {
// Turn 1
MESSAGE("You sense the presence of many!");
ABILITY_POPUP(opponent, ABILITY_POWER_CONSTRUCT);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_POWER_CONSTRUCT, opponent);
// Turn 2
ANIMATION(ANIM_TYPE_SPECIAL, B_ANIM_BALL_THROW, player);
} THEN {
EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_SPECIES), baseSpecies);
}
}

View File

@ -8,7 +8,6 @@ ASSUMPTIONS
ASSUME(MoveMakesContact(MOVE_SCRATCH) == TRUE); ASSUME(MoveMakesContact(MOVE_SCRATCH) == TRUE);
} }
SINGLE_BATTLE_TEST("Tangling Hair drops opposing mon's speed if ability user got hit by a contact move") SINGLE_BATTLE_TEST("Tangling Hair drops opposing mon's speed if ability user got hit by a contact move")
{ {
u32 move; u32 move;
@ -85,3 +84,16 @@ SINGLE_BATTLE_TEST("Tangling Hair does not activate on confusion damage")
} }
} }
} }
SINGLE_BATTLE_TEST("Tangling Hair does not trigger on Clear Body")
{
GIVEN {
PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_TANGLING_HAIR); }
OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); };
} WHEN {
TURN { MOVE(opponent, MOVE_SCRATCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
NOT ABILITY_POPUP(player, ABILITY_TANGLING_HAIR);
}
}

View File

@ -1,9 +1,24 @@
#include "global.h" #include "global.h"
#include "test/battle.h" #include "test/battle.h"
SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting") SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting (start as Shield)")
{
GIVEN {
PLAYER(SPECIES_AEGISLASH_SHIELD) { HP(1); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_GUST); SEND_OUT(player, 1); }
} SCENE {
MESSAGE("The opposing Wobbuffet used Gust!");
MESSAGE("Aegislash fainted!");
} THEN {
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_AEGISLASH_SHIELD);
}
}
SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting (start as Blade)")
{ {
KNOWN_FAILING;
GIVEN { GIVEN {
PLAYER(SPECIES_AEGISLASH_BLADE) { HP(1); } PLAYER(SPECIES_AEGISLASH_BLADE) { HP(1); }
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
@ -14,7 +29,7 @@ SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting")
MESSAGE("The opposing Wobbuffet used Gust!"); MESSAGE("The opposing Wobbuffet used Gust!");
MESSAGE("Aegislash fainted!"); MESSAGE("Aegislash fainted!");
} THEN { } THEN {
EXPECT_EQ(GetMonData(&PLAYER_PARTY[0], MON_DATA_SPECIES), SPECIES_AEGISLASH_SHIELD); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_AEGISLASH_SHIELD);
} }
} }

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") SINGLE_BATTLE_TEST("Belly Drum fails if the user's Attack is already at +6, even with Contrary")
{ {
KNOWN_FAILING;
GIVEN { GIVEN {
ASSUME(GetMoveEffect(MOVE_CHARM) == EFFECT_ATTACK_DOWN_2); ASSUME(GetMoveEffect(MOVE_CHARM) == EFFECT_ATTACK_DOWN_2);
PLAYER(SPECIES_SERPERIOR) { Ability(ABILITY_CONTRARY); } 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") SINGLE_BATTLE_TEST("Belly Drum deducts HP if the user has Contrary and is at -6")
{ {
KNOWN_FAILING;
GIVEN { GIVEN {
ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2);
PLAYER(SPECIES_SERPERIOR) { Ability(ABILITY_CONTRARY); } 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); ANIMATION(ANIM_TYPE_MOVE, MOVE_BELLY_DRUM, player);
s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP); s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP);
HP_BAR(player, hp: maxHP / 2); 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!");
} }
} }

View File

@ -113,7 +113,7 @@ SINGLE_BATTLE_TEST("Hit Escape: U-turn switches the user out after Ice Face acti
} }
} }
SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: player side") SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn: player side")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };
@ -126,7 +126,6 @@ SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon
ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE); ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
HP_BAR(opponent); HP_BAR(opponent);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("2 sent out Wynaut!"); MESSAGE("2 sent out Wynaut!");
@ -136,7 +135,7 @@ SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon
} }
} }
SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side") SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn: opposing side")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };
@ -149,7 +148,6 @@ SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon
ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE); ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
HP_BAR(opponent); HP_BAR(opponent);
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
MESSAGE("2 sent out Wynaut!"); MESSAGE("2 sent out Wynaut!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);