10/11/25 Master to upcoming merge
This commit is contained in:
commit
d4e7e7ad36
@ -189,8 +189,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
|
||||
|
||||
@ -3685,7 +3685,7 @@ BattleScript_BlockedByPrimalWeatherRet::
|
||||
|
||||
BattleScript_EffectBellyDrum::
|
||||
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
|
||||
attackanimation
|
||||
waitanimation
|
||||
@ -7440,11 +7440,13 @@ BattleScript_CuteCharmActivates::
|
||||
return
|
||||
|
||||
BattleScript_GooeyActivates::
|
||||
statbuffchange BS_ATTACKER, STAT_CHANGE_ONLY_CHECKING, BattleScript_GooeyActivatesRet
|
||||
waitstate
|
||||
call BattleScript_AbilityPopUp
|
||||
swapattackerwithtarget @ for defiant, mirror armor
|
||||
seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_SPD_MINUS_1
|
||||
swapattackerwithtarget
|
||||
BattleScript_GooeyActivatesRet:
|
||||
return
|
||||
|
||||
BattleScript_AbilityStatusEffect::
|
||||
|
||||
@ -315,6 +315,7 @@ bool32 IsBattlerMegaEvolved(u32 battler);
|
||||
bool32 IsBattlerPrimalReverted(u32 battler);
|
||||
bool32 IsBattlerUltraBursted(u32 battler);
|
||||
u16 GetBattleFormChangeTargetSpecies(u32 battler, enum FormChanges method);
|
||||
bool32 TryRevertPartyMonFormChange(u32 partyIndex);
|
||||
bool32 TryBattleFormChange(u32 battler, enum FormChanges method);
|
||||
bool32 DoBattlersShareType(u32 battler1, u32 battler2);
|
||||
bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId);
|
||||
@ -346,7 +347,7 @@ void TrySaveExchangedItem(u32 battler, u16 stolenItem);
|
||||
bool32 IsPartnerMonFromSameTrainer(u32 battler);
|
||||
bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes);
|
||||
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 PickupHasValidTarget(u32 battler);
|
||||
bool32 CantPickupItem(u32 battler);
|
||||
|
||||
@ -461,6 +461,7 @@ void HandleInputChooseTarget(u32 battler)
|
||||
gBattleStruct->zmove.viewing = TRUE;
|
||||
ReloadMoveNames(battler);
|
||||
}
|
||||
TryToAddMoveInfoWindow();
|
||||
DoBounceEffect(battler, BOUNCE_HEALTHBOX, 7, 1);
|
||||
DoBounceEffect(battler, BOUNCE_MON, 7, 1);
|
||||
EndBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX);
|
||||
|
||||
@ -77,7 +77,7 @@ enum ItemEffect TryBoosterEnergy(u32 battler, enum Ability ability, ActivationTi
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
SET_STATCHANGER(statId, 1, FALSE);
|
||||
@ -423,7 +423,7 @@ static enum ItemEffect TryBlunderPolicy(u32 battlerAtk)
|
||||
|
||||
if (gBattleStruct->blunderPolicy
|
||||
&& 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;
|
||||
SET_STATCHANGER(STAT_SPEED, 2, FALSE);
|
||||
@ -502,7 +502,7 @@ static enum ItemEffect TryThroatSpray(u32 battlerAtk)
|
||||
&& gMultiHitCounter == 0
|
||||
&& IsBattlerAlive(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
|
||||
{
|
||||
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
||||
@ -517,7 +517,7 @@ static enum ItemEffect DamagedStatBoostBerryEffect(u32 battlerDef, u32 battlerAt
|
||||
{
|
||||
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;
|
||||
|
||||
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 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))
|
||||
{
|
||||
gEffectBattler = gBattleScripting.battler = battler;
|
||||
@ -1011,17 +1011,17 @@ static enum ItemEffect RandomStatRaiseBerry(u32 battler, u32 itemId, ActivationT
|
||||
{
|
||||
enum ItemEffect effect = ITEM_NO_EFFECT;
|
||||
enum Stat stat;
|
||||
enum Ability ability = 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, ability))
|
||||
break;
|
||||
}
|
||||
|
||||
if (stat == NUM_STATS)
|
||||
return effect;
|
||||
|
||||
enum Ability ability = GetBattlerAbility(battler);
|
||||
if (HasEnoughHpToEatBerry(battler, ability, GetItemHoldEffectParam(itemId), itemId))
|
||||
{
|
||||
u32 savedAttacker = gBattlerAttacker;
|
||||
|
||||
@ -5642,19 +5642,8 @@ static void HandleEndTurn_FinishBattle(void)
|
||||
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
bool8 changedForm = FALSE;
|
||||
|
||||
// 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;
|
||||
|
||||
bool32 changedForm = TryRevertPartyMonFormChange(i);
|
||||
|
||||
// Recalculate the stats of every party member before the end
|
||||
if (!changedForm && B_RECALCULATE_STATS >= GEN_5)
|
||||
CalculateMonStats(&gPlayerParty[i]);
|
||||
|
||||
@ -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
|
||||
@ -4384,7 +4384,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;
|
||||
@ -4392,8 +4392,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)
|
||||
@ -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)
|
||||
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)
|
||||
@ -5612,17 +5626,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++;
|
||||
@ -5853,7 +5867,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);
|
||||
@ -6118,7 +6132,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);
|
||||
@ -11912,7 +11926,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;
|
||||
@ -13892,6 +13906,8 @@ static void Cmd_givecaughtmon(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
//Before sending to PC, we revert battle form
|
||||
TryRevertPartyMonFormChange(gSelectedMonPartyId);
|
||||
// Mon chosen, try to put it in the PC
|
||||
if (CopyMonToPC(&gPlayerParty[gSelectedMonPartyId]) == MON_GIVEN_TO_PC)
|
||||
{
|
||||
@ -15690,7 +15706,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;
|
||||
@ -16705,7 +16721,7 @@ void BS_TryAcupressure(void)
|
||||
u32 bits = 0;
|
||||
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;
|
||||
}
|
||||
if (bits)
|
||||
@ -17104,10 +17120,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);
|
||||
@ -17922,11 +17939,12 @@ void BS_SetAttackerToStickyWebUser(void)
|
||||
void BS_CutOneThirdHpAndRaiseStats(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
|
||||
bool32 atLeastOneStatBoosted = FALSE;
|
||||
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;
|
||||
|
||||
@ -66,6 +66,7 @@ static u32 GetFlingPowerFromItemId(u32 itemId);
|
||||
static void SetRandomMultiHitCounter();
|
||||
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 IsOpposingSideEmpty(u32 battler);
|
||||
|
||||
// Submoves
|
||||
static u32 GetMirrorMoveMove(void);
|
||||
@ -1237,7 +1238,7 @@ void PrepareStringBattle(enum StringID stringId, u32 battler)
|
||||
case STRINGID_PKMNCUTSATTACKWITH:
|
||||
if (GetGenConfig(GEN_CONFIG_UPDATED_INTIMIDATE) >= GEN_8
|
||||
&& 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);
|
||||
@ -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
|
||||
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)
|
||||
@ -3540,7 +3541,7 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability ability
|
||||
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))
|
||||
{
|
||||
battleScript = BattleScript_MonMadeMoveUseless;
|
||||
}
|
||||
@ -4119,7 +4120,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
|
||||
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);
|
||||
@ -4272,7 +4273,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
}
|
||||
break;
|
||||
case ABILITY_INTIMIDATE:
|
||||
if (!gSpecialStatuses[battler].switchInAbilityDone)
|
||||
if (!gSpecialStatuses[battler].switchInAbilityDone && !IsOpposingSideEmpty(battler))
|
||||
{
|
||||
SaveBattlerAttacker(gBattlerAttacker);
|
||||
gBattlerAttacker = battler;
|
||||
@ -4284,7 +4285,8 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
break;
|
||||
case ABILITY_SUPERSWEET_SYRUP:
|
||||
if (!gSpecialStatuses[battler].switchInAbilityDone
|
||||
&& !GetBattlerPartyState(battler)->supersweetSyrup)
|
||||
&& !GetBattlerPartyState(battler)->supersweetSyrup
|
||||
&& !IsOpposingSideEmpty(battler))
|
||||
{
|
||||
SaveBattlerAttacker(gBattlerAttacker);
|
||||
gBattlerAttacker = battler;
|
||||
@ -4331,7 +4333,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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);
|
||||
@ -4346,7 +4348,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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);
|
||||
@ -4356,7 +4358,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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;
|
||||
@ -4496,7 +4498,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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;
|
||||
@ -4646,7 +4648,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
}
|
||||
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)
|
||||
{
|
||||
SaveBattlerAttacker(gBattlerAttacker);
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -4807,7 +4809,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
if (IsBattlerTurnDamaged(battler)
|
||||
&& IsBattlerAlive(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;
|
||||
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
||||
@ -4836,7 +4838,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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 = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_ATK, 1, FALSE);
|
||||
@ -4848,7 +4850,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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 = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_SPEED, 1, FALSE);
|
||||
@ -4860,7 +4862,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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 = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_DEF, 2, FALSE);
|
||||
@ -4872,7 +4874,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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 = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_DEF, 1, FALSE);
|
||||
@ -4884,8 +4886,8 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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
|
||||
@ -4964,7 +4966,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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);
|
||||
@ -4974,7 +4976,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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), move))
|
||||
@ -5178,7 +5180,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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 = gBattlerAbility = battler;
|
||||
@ -5260,7 +5262,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
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 = gBattlerAbility = gBattlerTarget;
|
||||
@ -9052,17 +9054,46 @@ bool32 CanBattlerFormChange(u32 battler, enum FormChanges method)
|
||||
if (gBattleMons[battler].volatiles.transformed
|
||||
&& B_TRANSFORM_FORM_CHANGES >= GEN_5)
|
||||
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))
|
||||
return TRUE;
|
||||
else if (IsBattlerPrimalReverted(battler) && (method == FORM_CHANGE_END_BATTLE))
|
||||
return TRUE;
|
||||
// Gigantamaxed Pokemon should revert upon fainting, switching, or ending the battle.
|
||||
else if (IsGigantamaxed(battler) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_BATTLE_SWITCH || method == FORM_CHANGE_END_BATTLE))
|
||||
return TRUE;
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case FORM_CHANGE_END_BATTLE:
|
||||
if (IsBattlerPrimalReverted(battler))
|
||||
return TRUE;
|
||||
// Fallthrough
|
||||
case FORM_CHANGE_FAINT:
|
||||
if (IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler) || IsGigantamaxed(battler))
|
||||
return TRUE;
|
||||
break;
|
||||
case FORM_CHANGE_BATTLE_SWITCH:
|
||||
if (IsGigantamaxed(battler))
|
||||
return TRUE;
|
||||
else if (GetActiveGimmick(battler) == GIMMICK_TERA && GetBattlerAbility(battler) == ABILITY_HUNGER_SWITCH)
|
||||
return FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
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)
|
||||
{
|
||||
u32 monId = gBattlerPartyIndexes[battler];
|
||||
@ -9076,7 +9107,7 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method)
|
||||
targetSpecies = GetBattleFormChangeTargetSpecies(battler, method);
|
||||
if (targetSpecies == currentSpecies)
|
||||
targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0);
|
||||
if (targetSpecies != currentSpecies)
|
||||
if (targetSpecies != currentSpecies && targetSpecies != SPECIES_NONE)
|
||||
{
|
||||
// Saves the original species on the first form change.
|
||||
|
||||
@ -9093,17 +9124,22 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method)
|
||||
{
|
||||
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.
|
||||
if ((IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE))
|
||||
restoreSpecies = TRUE;
|
||||
|
||||
// Unlike Megas, Primal Reversion isn't canceled on fainting.
|
||||
else if (IsBattlerPrimalReverted(battler) && (method == FORM_CHANGE_END_BATTLE))
|
||||
restoreSpecies = TRUE;
|
||||
|
||||
// Gigantamax Pokemon have their forms reverted after fainting, switching, or ending the battle.
|
||||
else if (IsGigantamaxed(battler) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_BATTLE_SWITCH || method == FORM_CHANGE_END_BATTLE))
|
||||
switch (method)
|
||||
{
|
||||
case FORM_CHANGE_END_BATTLE:
|
||||
restoreSpecies = TRUE;
|
||||
break;
|
||||
case FORM_CHANGE_FAINT:
|
||||
if (IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler) || IsGigantamaxed(battler))
|
||||
restoreSpecies = TRUE;
|
||||
break;
|
||||
case FORM_CHANGE_BATTLE_SWITCH:
|
||||
if (IsGigantamaxed(battler))
|
||||
restoreSpecies = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
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;
|
||||
@ -10772,6 +10808,21 @@ bool32 HasPartnerTrainer(u32 battler)
|
||||
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)
|
||||
{
|
||||
s32 i, validMovesCount;
|
||||
|
||||
@ -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);
|
||||
@ -1306,15 +1306,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;
|
||||
|
||||
@ -1511,7 +1511,7 @@ static void HandleChooseMonSelection(u8 taskId, s8 *slotPtr)
|
||||
}
|
||||
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))
|
||||
{
|
||||
// Can't select if mon is currently on the field
|
||||
@ -1538,7 +1538,7 @@ static void HandleChooseMonSelection(u8 taskId, s8 *slotPtr)
|
||||
else
|
||||
{
|
||||
PlaySE(SE_SELECT);
|
||||
gSelectedMonPartyId = partyId;
|
||||
gSelectedMonPartyId = GetPartyIdFromBattleSlot(partyId);
|
||||
Task_ClosePartyMenu(taskId);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -399,6 +399,7 @@ bool8 CheckForTrainersWantingBattle(void)
|
||||
if (numTrainers == 0xFF) // non-trainerbattle script
|
||||
{
|
||||
u32 objectEventId = gApproachingTrainers[gNoOfApproachingTrainers - 1].objectEventId;
|
||||
gApproachingTrainers[gNoOfApproachingTrainers - 1].trainerScriptPtr = GetObjectEventScriptPointerByObjectEventId(objectEventId);
|
||||
gSelectedObjectEvent = objectEventId;
|
||||
gSpecialVar_LastTalked = gObjectEvents[objectEventId].localId;
|
||||
ScriptContext_SetupScript(EventScript_ObjectApproachPlayer);
|
||||
|
||||
@ -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")
|
||||
{
|
||||
KNOWN_FAILING; // #7062
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_ROAR) == EFFECT_ROAR);
|
||||
PLAYER(SPECIES_MORPEKO) { Ability(ABILITY_HUNGER_SWITCH); TeraType(TYPE_NORMAL); }
|
||||
|
||||
@ -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_U_TURN, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
NOT ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
|
||||
MESSAGE("2 sent out Treecko!");
|
||||
MESSAGE("2 sent out Torchic!");
|
||||
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;
|
||||
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);
|
||||
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} 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 {
|
||||
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_NEUTRALIZING_GAS);
|
||||
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!");
|
||||
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE);
|
||||
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 {
|
||||
ASSUME(GetMoveEffect(MOVE_FELL_STINGER) == EFFECT_FELL_STINGER);
|
||||
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_FELL_STINGER); SEND_OUT(player, 1); }
|
||||
TURN { MOVE(opponentLeft, MOVE_FELL_STINGER, target: playerLeft); SEND_OUT(playerLeft, 2); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_NEUTRALIZING_GAS);
|
||||
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!");
|
||||
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE);
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,3 +2,56 @@
|
||||
#include "test/battle.h"
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ ASSUMPTIONS
|
||||
ASSUME(MoveMakesContact(MOVE_SCRATCH) == TRUE);
|
||||
}
|
||||
|
||||
|
||||
SINGLE_BATTLE_TEST("Tangling Hair drops opposing mon's speed if ability user got hit by a contact 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,24 @@
|
||||
#include "global.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 {
|
||||
PLAYER(SPECIES_AEGISLASH_BLADE) { HP(1); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
@ -14,7 +29,7 @@ SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting")
|
||||
MESSAGE("The opposing Wobbuffet used Gust!");
|
||||
MESSAGE("Aegislash fainted!");
|
||||
} THEN {
|
||||
EXPECT_EQ(GetMonData(&PLAYER_PARTY[0], MON_DATA_SPECIES), SPECIES_AEGISLASH_SHIELD);
|
||||
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_AEGISLASH_SHIELD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
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);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
|
||||
HP_BAR(opponent);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
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 {
|
||||
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);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
|
||||
HP_BAR(opponent);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user