Fixes activation order for a couple abilities (#7732)
This commit is contained in:
parent
f9a8a0251a
commit
3c9f05b367
@ -1011,8 +1011,9 @@
|
||||
.4byte \jumpInstr
|
||||
.endm
|
||||
|
||||
.macro tryrestorehpberry
|
||||
.macro tryrestorehpberry battler:req
|
||||
.byte 0xbb
|
||||
.byte \battler
|
||||
.endm
|
||||
|
||||
.macro halvehp failInstr:req
|
||||
|
||||
@ -4966,7 +4966,7 @@ BattleScript_MagicRoomEnds::
|
||||
setbyte gBattlerTarget, 0
|
||||
BattleScript_MagicRoomHealingItemsLoop:
|
||||
copyarraywithindex gBattlerAttacker, gBattlerByTurnOrder, gBattlerTarget, 1
|
||||
tryrestorehpberry
|
||||
tryrestorehpberry BS_ATTACKER
|
||||
addbyte gBattlerTarget, 1
|
||||
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_MagicRoomHealingItemsLoop
|
||||
end2
|
||||
@ -5404,27 +5404,36 @@ BattleScript_SeedSowerActivates::
|
||||
call BattleScript_ActivateTerrainEffects
|
||||
return
|
||||
|
||||
BattleScript_AngerShellActivates::
|
||||
BattleScript_BerserkActivates::
|
||||
saveattacker
|
||||
copybyte gBattlerAttacker, gBattlerTarget
|
||||
copybyte gBattlerAttacker, gEffectBattler
|
||||
call BattleScript_AbilityPopUp
|
||||
jumpifstat BS_TARGET, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_AngerShellTryDef
|
||||
jumpifstat BS_TARGET, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_AngerShellTryDef
|
||||
jumpifstat BS_TARGET, CMP_LESS_THAN, STAT_SPEED, MAX_STAT_STAGE, BattleScript_AngerShellTryDef
|
||||
jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_AngerShellTryDef
|
||||
jumpifstat BS_TARGET, CMP_EQUAL, STAT_SPDEF, MIN_STAT_STAGE, BattleScript_RestoreAttackerButItFailed
|
||||
BattleScript_AngerShellTryDef::
|
||||
modifybattlerstatstage BS_ATTACKER, STAT_DEF, DECREASE, 1, BattleScript_AngerShellTrySpDef, ANIM_ON
|
||||
BattleScript_AngerShellTrySpDef:
|
||||
modifybattlerstatstage BS_ATTACKER, STAT_SPDEF, DECREASE, 1, BattleScript_AngerShellTryAttack, ANIM_ON
|
||||
BattleScript_AngerShellTryAttack:
|
||||
modifybattlerstatstage BS_ATTACKER, STAT_ATK, INCREASE, 1, BattleScript_AngerShellTrySpAtk, ANIM_ON
|
||||
BattleScript_AngerShellTrySpAtk:
|
||||
modifybattlerstatstage BS_ATTACKER, STAT_SPATK, INCREASE, 1, BattleScript_AngerShellTrySpeed, ANIM_ON
|
||||
BattleScript_AngerShellTrySpeed:
|
||||
modifybattlerstatstage BS_ATTACKER, STAT_SPEED, INCREASE, 1, BattleScript_AngerShellRet, ANIM_ON
|
||||
BattleScript_AngerShellRet:
|
||||
statbuffchange BS_EFFECT_BATTLER, STAT_CHANGE_CERTAIN, BattleScript_BerserkActivatesTryBerry
|
||||
call BattleScript_StatUp
|
||||
BattleScript_BerserkActivatesTryBerry:
|
||||
restoreattacker
|
||||
tryrestorehpberry BS_EFFECT_BATTLER
|
||||
return
|
||||
|
||||
BattleScript_AngerShellActivates::
|
||||
call BattleScript_AbilityPopUp
|
||||
jumpifstat BS_EFFECT_BATTLER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_AngerShellTryDef
|
||||
jumpifstat BS_EFFECT_BATTLER, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_AngerShellTryDef
|
||||
jumpifstat BS_EFFECT_BATTLER, CMP_LESS_THAN, STAT_SPEED, MAX_STAT_STAGE, BattleScript_AngerShellTryDef
|
||||
jumpifstat BS_EFFECT_BATTLER, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_AngerShellTryDef
|
||||
jumpifstat BS_EFFECT_BATTLER, CMP_EQUAL, STAT_SPDEF, MIN_STAT_STAGE, BattleScript_RestoreAttackerButItFailed
|
||||
BattleScript_AngerShellTryDef::
|
||||
modifybattlerstatstage BS_EFFECT_BATTLER, STAT_DEF, DECREASE, 1, BattleScript_AngerShellTrySpDef, ANIM_ON
|
||||
BattleScript_AngerShellTrySpDef:
|
||||
modifybattlerstatstage BS_EFFECT_BATTLER, STAT_SPDEF, DECREASE, 1, BattleScript_AngerShellTryAttack, ANIM_ON
|
||||
BattleScript_AngerShellTryAttack:
|
||||
modifybattlerstatstage BS_EFFECT_BATTLER, STAT_ATK, INCREASE, 1, BattleScript_AngerShellTrySpAtk, ANIM_ON
|
||||
BattleScript_AngerShellTrySpAtk:
|
||||
modifybattlerstatstage BS_EFFECT_BATTLER, STAT_SPATK, INCREASE, 1, BattleScript_AngerShellTrySpeed, ANIM_ON
|
||||
BattleScript_AngerShellTrySpeed:
|
||||
modifybattlerstatstage BS_EFFECT_BATTLER, STAT_SPEED, INCREASE, 1, BattleScript_AngerShellRet, ANIM_ON
|
||||
BattleScript_AngerShellRet:
|
||||
tryrestorehpberry BS_EFFECT_BATTLER
|
||||
return
|
||||
|
||||
BattleScript_WindPowerActivates::
|
||||
@ -5557,8 +5566,10 @@ BattleScript_DoFutureAttackResult:
|
||||
tryfaintmon BS_TARGET
|
||||
checkteamslost BattleScript_FutureAttackEnd
|
||||
BattleScript_FutureAttackEnd::
|
||||
moveendcase MOVEEND_SET_VALUES
|
||||
moveendcase MOVEEND_RAGE
|
||||
moveendcase MOVEEND_ABILITIES
|
||||
moveendcase MOVEEND_COLOR_CHANGE
|
||||
moveendfromto MOVEEND_ITEM_EFFECTS_ALL, MOVEEND_UPDATE_LAST_MOVES
|
||||
setmoveresultflags 0
|
||||
end2
|
||||
@ -6142,7 +6153,7 @@ BattleScript_DoTurnDmg:
|
||||
datahpupdate BS_ATTACKER
|
||||
tryfaintmon BS_ATTACKER
|
||||
checkteamslost BattleScript_DoTurnDmgEnd
|
||||
tryrestorehpberry
|
||||
tryrestorehpberry BS_ATTACKER
|
||||
BattleScript_DoTurnDmgEnd:
|
||||
end2
|
||||
|
||||
@ -6384,7 +6395,7 @@ BattleScript_YawnEnd:
|
||||
BattleScript_EmbargoEndTurn::
|
||||
printstring STRINGID_EMBARGOENDS
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
tryrestorehpberry
|
||||
tryrestorehpberry BS_ATTACKER
|
||||
end2
|
||||
|
||||
BattleScript_TelekinesisEndTurn::
|
||||
@ -6674,7 +6685,7 @@ BattleScript_PickupActivates::
|
||||
call BattleScript_AbilityPopUp
|
||||
printstring STRINGID_XFOUNDONEY
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
tryrestorehpberry
|
||||
tryrestorehpberry BS_ATTACKER
|
||||
BattleScript_PickupActivatesEnd:
|
||||
end2
|
||||
|
||||
@ -6684,7 +6695,7 @@ BattleScript_HarvestActivates::
|
||||
call BattleScript_AbilityPopUp
|
||||
printstring STRINGID_HARVESTBERRY
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
tryrestorehpberry
|
||||
tryrestorehpberry BS_ATTACKER
|
||||
BattleScript_HarvestActivatesEnd:
|
||||
end2
|
||||
|
||||
@ -8174,6 +8185,10 @@ BattleScript_OpportunistStartCopyStats:
|
||||
goto BattleScript_OpportunistStartCopyStats
|
||||
BattleScript_OpportunistCopyStatChangeEnd:
|
||||
setbyte sSTAT_ANIM_PLAYED, FALSE
|
||||
return
|
||||
|
||||
BattleScript_OpportunistCopyStatChangeEnd3::
|
||||
call BattleScript_OpportunistCopyStatChange
|
||||
end3
|
||||
|
||||
BattleScript_TotemVar::
|
||||
@ -8593,14 +8608,13 @@ BattleScript_SymbiosisActivates::
|
||||
return
|
||||
|
||||
BattleScript_TargetAbilityStatRaiseRet::
|
||||
copybyte sSAVED_BATTLER, gBattlerAttacker
|
||||
copybyte gBattlerAbility, gEffectBattler
|
||||
copybyte gBattlerAttacker, gBattlerTarget
|
||||
saveattacker
|
||||
copybyte gBattlerAttacker, gEffectBattler
|
||||
call BattleScript_AbilityPopUp
|
||||
statbuffchange BS_ATTACKER, STAT_CHANGE_CERTAIN, BattleScript_TargetAbilityStatRaiseRet_End
|
||||
call BattleScript_StatUp
|
||||
BattleScript_TargetAbilityStatRaiseRet_End:
|
||||
copybyte gBattlerAttacker, sSAVED_BATTLER
|
||||
restoreattacker
|
||||
return
|
||||
|
||||
@@@ MAX MOVES @@@
|
||||
|
||||
@ -607,8 +607,9 @@ struct BattleStruct
|
||||
struct BattlerState battlerState[MAX_BATTLERS_COUNT];
|
||||
struct PartyState partyState[NUM_BATTLE_SIDES][PARTY_SIZE];
|
||||
u8 eventBlockCounter;
|
||||
u8 turnEffectsBattlerId;
|
||||
u8 endTurnEventsCounter;
|
||||
u8 turnEffectsBattlerId:4;
|
||||
u8 moveEndBattlerId:4;
|
||||
u16 wrappedMove[MAX_BATTLERS_COUNT];
|
||||
u16 moveTarget[MAX_BATTLERS_COUNT];
|
||||
u32 expShareExpValue;
|
||||
@ -779,7 +780,8 @@ struct BattleStruct
|
||||
u8 numHazards[NUM_BATTLE_SIDES];
|
||||
u8 hazardsCounter:4; // Counter for applying hazard on switch in
|
||||
enum SubmoveState submoveAnnouncement:2;
|
||||
u8 padding2:2;
|
||||
u8 toxicChainPriority:1; // If Toxic Chain will trigger on target, all other non volatiles will be blocked
|
||||
u8 padding2:1;
|
||||
};
|
||||
|
||||
struct AiBattleData
|
||||
@ -901,7 +903,7 @@ struct BattleScripting
|
||||
s32 savedDmg;
|
||||
u16 savedMoveEffect; // For moves hitting multiple targets.
|
||||
u16 moveEffect;
|
||||
u16 multihitMoveEffect;
|
||||
u16 unused_0x30;
|
||||
u8 illusionNickHack; // To properly display nick in STRINGID_ENEMYABOUTTOSWITCHPKMN.
|
||||
bool8 fixedPopup; // Force ability popup to stick until manually called back
|
||||
u16 abilityPopupOverwrite;
|
||||
|
||||
@ -57,9 +57,9 @@ enum FirstTurnEventsStates
|
||||
FIRST_TURN_EVENTS_TOTEM_BOOST,
|
||||
FIRST_TURN_EVENTS_NEUTRALIZING_GAS,
|
||||
FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES,
|
||||
FIRST_TURN_EVENTS_OPPORTUNIST_1,
|
||||
FIRST_TURN_EVENTS_ITEM_EFFECTS,
|
||||
FIRST_TURN_EVENTS_OPPORTUNIST_2,
|
||||
FIRST_TURN_EVENTS_OPPORTUNIST,
|
||||
FIRST_TURN_EVENTS_MIRROR_HERB,
|
||||
FIRST_TURN_EVENTS_EJECT_PACK,
|
||||
FIRST_TURN_EVENTS_END,
|
||||
};
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
extern const u8 BattleScript_SupersweetSyrupActivates[];
|
||||
extern const u8 BattleScript_OpportunistCopyStatChange[];
|
||||
extern const u8 BattleScript_OpportunistCopyStatChangeEnd3[];
|
||||
extern const u8 BattleScript_MirrorHerbCopyStatChange[];
|
||||
extern const u8 BattleScript_MirrorHerbCopyStatChangeEnd2[];
|
||||
extern const u8 BattleScript_NotAffected[];
|
||||
@ -461,6 +462,7 @@ extern const u8 BattleScript_RemoveFireType[];
|
||||
extern const u8 BattleScript_TargetAbilityStatRaiseRet[];
|
||||
extern const u8 BattleScript_RemoveElectricType[];
|
||||
extern const u8 BattleScript_SeedSowerActivates[];
|
||||
extern const u8 BattleScript_BerserkActivates[];
|
||||
extern const u8 BattleScript_AngerShellActivates[];
|
||||
extern const u8 BattleScript_WellBakedBodyActivates[];
|
||||
extern const u8 BattleScript_WindRiderActivatesMoveEnd[];
|
||||
|
||||
@ -43,6 +43,7 @@ enum {
|
||||
ABILITYEFFECT_ON_SWITCHIN,
|
||||
ABILITYEFFECT_ENDTURN,
|
||||
ABILITYEFFECT_MOVE_END_ATTACKER,
|
||||
ABILITYEFFECT_COLOR_CHANGE, // Color Change, Berserk, Anger Shell
|
||||
ABILITYEFFECT_MOVE_END,
|
||||
ABILITYEFFECT_IMMUNITY,
|
||||
ABILITYEFFECT_SYNCHRONIZE,
|
||||
@ -55,6 +56,7 @@ enum {
|
||||
ABILITYEFFECT_SWITCH_IN_TERRAIN,
|
||||
ABILITYEFFECT_SWITCH_IN_WEATHER,
|
||||
ABILITYEFFECT_OPPORTUNIST,
|
||||
ABILITYEFFECT_OPPORTUNIST_FIRST_TURN,
|
||||
ABILITYEFFECT_SWITCH_IN_STATUSES,
|
||||
};
|
||||
|
||||
@ -64,6 +66,7 @@ enum ItemCaseId
|
||||
ITEMEFFECT_NONE,
|
||||
ITEMEFFECT_ON_SWITCH_IN,
|
||||
ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN,
|
||||
ITEMEFFECT_LEFTOVERS, // Leftovers, Black Sludge
|
||||
ITEMEFFECT_NORMAL,
|
||||
ITEMEFFECT_TRY_HEALING,
|
||||
ITEMEFFECT_MOVE_END,
|
||||
@ -74,6 +77,8 @@ enum ItemCaseId
|
||||
ITEMEFFECT_USE_LAST_ITEM, // move end effects for just the battler, not whole field
|
||||
ITEMEFFECT_WHITE_HERB,
|
||||
ITEMEFFECT_WHITE_HERB_ENDTURN,
|
||||
ITEMEFFECT_MIRROR_HERB,
|
||||
ITEMEFFECT_MIRROR_HERB_FIRST_TURN,
|
||||
};
|
||||
|
||||
enum ItemEffect
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#define sSAVED_DMG (gBattleScripting + 0x28) // savedDmg
|
||||
#define sSAVED_MOVE_EFFECT (gBattleScripting + 0x2C) // savedMoveEffect
|
||||
#define sMOVE_EFFECT (gBattleScripting + 0x2E) // moveEffect
|
||||
#define sMULTIHIT_EFFECT (gBattleScripting + 0x30) // multihitMoveEffect
|
||||
#define sUNUSED_0x30 (gBattleScripting + 0x30) // unused_0x30
|
||||
#define sILLUSION_NICK_HACK (gBattleScripting + 0x32) // illusionNickHack
|
||||
#define sFIXED_ABILITY_POPUP (gBattleScripting + 0x33) // fixedPopup
|
||||
#define sABILITY_OVERWRITE (gBattleScripting + 0x34) // abilityPopupOverwrite
|
||||
@ -128,7 +128,7 @@ enum CmdVarious
|
||||
// cases for Cmd_moveend - Order matters!
|
||||
enum MoveEndEffects
|
||||
{
|
||||
MOVEEND_SUM_DAMAGE,
|
||||
MOVEEND_SET_VALUES,
|
||||
MOVEEND_PROTECT_LIKE_EFFECT,
|
||||
MOVEEND_ABSORB,
|
||||
MOVEEND_RAGE,
|
||||
@ -155,14 +155,16 @@ enum MoveEndEffects
|
||||
MOVEEND_ITEM_EFFECTS_ATTACKER,
|
||||
MOVEEND_ABILITY_BLOCK,
|
||||
MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip until Opportunist
|
||||
MOVEEND_COLOR_CHANGE, // Color Change / Berserk / Anger Shell
|
||||
MOVEEND_RED_CARD, // Red Card triggers before Eject Pack
|
||||
MOVEEND_EJECT_BUTTON,
|
||||
MOVEEND_LIFEORB_SHELLBELL, // Includes shell bell, throat spray, etc
|
||||
MOVEEND_LIFEORB_SHELLBELL, // Shell Bell / Life Orb / Throat Spray
|
||||
MOVEEND_FORM_CHANGE,
|
||||
MOVEEND_EMERGENCY_EXIT,
|
||||
MOVEEND_EJECT_PACK,
|
||||
MOVEEND_HIT_ESCAPE,
|
||||
MOVEEND_OPPORTUNIST, // Occurs after other stat change items/abilities to try and copy the boosts
|
||||
MOVEEND_MIRROR_HERB,
|
||||
MOVEEND_PICKPOCKET,
|
||||
MOVEEND_WHITE_HERB,
|
||||
MOVEEND_THIRD_MOVE_BLOCK,
|
||||
|
||||
@ -425,17 +425,22 @@ static bool32 HandleEndTurnWish(u32 battler)
|
||||
static bool32 HandleEndTurnFirstEventBlock(u32 battler)
|
||||
{
|
||||
bool32 effect = FALSE;
|
||||
|
||||
u32 side;
|
||||
|
||||
if (!IsBattlerAlive(battler))
|
||||
{
|
||||
gBattleStruct->eventBlockCounter = 0;
|
||||
gBattleStruct->turnEffectsBattlerId++;
|
||||
return effect;
|
||||
}
|
||||
|
||||
switch (gBattleStruct->eventBlockCounter)
|
||||
{
|
||||
case FIRST_EVENT_BLOCK_GMAX_MOVE_RESIDUAL: // TODO: Has to be split into 3 statuses and needs a queue
|
||||
side = GetBattlerSide(battler);
|
||||
if (gSideStatuses[side] & SIDE_STATUS_DAMAGE_NON_TYPES)
|
||||
{
|
||||
if (IsBattlerAlive(battler)
|
||||
&& !IS_BATTLER_OF_TYPE(battler, gSideTimers[side].damageNonTypesType)
|
||||
if (!IS_BATTLER_OF_TYPE(battler, gSideTimers[side].damageNonTypesType)
|
||||
&& !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
|
||||
{
|
||||
gBattlerAttacker = battler;
|
||||
@ -448,7 +453,7 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
|
||||
gBattleStruct->eventBlockCounter++;
|
||||
break;
|
||||
case FIRST_EVENT_BLOCK_SEA_OF_FIRE_DAMAGE:
|
||||
if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SEA_OF_FIRE && IsBattlerAlive(battler))
|
||||
if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SEA_OF_FIRE)
|
||||
{
|
||||
gBattlerAttacker = battler;
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8;
|
||||
@ -484,7 +489,6 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
|
||||
break;
|
||||
case FIRST_EVENT_BLOCK_GRASSY_TERRAIN_HEAL:
|
||||
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerAtMaxHp(battler)
|
||||
&& !gBattleMons[battler].volatiles.healBlock
|
||||
&& !IsSemiInvulnerable(battler, CHECK_ALL)
|
||||
@ -515,23 +519,12 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
|
||||
break;
|
||||
}
|
||||
case FIRST_EVENT_BLOCK_HEAL_ITEMS:
|
||||
{
|
||||
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE);
|
||||
switch (holdEffect)
|
||||
{
|
||||
case HOLD_EFFECT_LEFTOVERS:
|
||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||
if (ItemBattleEffects(ITEMEFFECT_NORMAL, battler))
|
||||
effect = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ItemBattleEffects(ITEMEFFECT_LEFTOVERS, battler))
|
||||
effect = TRUE;
|
||||
gBattleStruct->eventBlockCounter = 0;
|
||||
gBattleStruct->turnEffectsBattlerId++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
@ -3864,23 +3864,18 @@ static void TryDoEventsBeforeFirstTurn(void)
|
||||
case FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES:
|
||||
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
|
||||
{
|
||||
i = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];
|
||||
u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];
|
||||
|
||||
if (TryPrimalReversion(i))
|
||||
if (TryPrimalReversion(battler))
|
||||
return;
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, 0, 0, 0) != 0)
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battler, 0, 0, 0))
|
||||
return;
|
||||
if (TryClearIllusion(i, ABILITYEFFECT_ON_SWITCHIN))
|
||||
if (TryClearIllusion(battler, ABILITYEFFECT_ON_SWITCHIN))
|
||||
return;
|
||||
}
|
||||
gBattleStruct->switchInBattlerCounter = 0;
|
||||
gBattleStruct->eventsBeforeFirstTurnState++;
|
||||
break;
|
||||
case FIRST_TURN_EVENTS_OPPORTUNIST_1:
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
|
||||
return;
|
||||
gBattleStruct->eventsBeforeFirstTurnState++;
|
||||
break;
|
||||
case FIRST_TURN_EVENTS_ITEM_EFFECTS:
|
||||
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
|
||||
{
|
||||
@ -3890,9 +3885,23 @@ static void TryDoEventsBeforeFirstTurn(void)
|
||||
gBattleStruct->switchInBattlerCounter = 0;
|
||||
gBattleStruct->eventsBeforeFirstTurnState++;
|
||||
break;
|
||||
case FIRST_TURN_EVENTS_OPPORTUNIST_2:
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
|
||||
return;
|
||||
case FIRST_TURN_EVENTS_OPPORTUNIST:
|
||||
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
|
||||
{
|
||||
u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST_FIRST_TURN, battler, GetBattlerAbility(battler), 0, 0))
|
||||
return;
|
||||
}
|
||||
gBattleStruct->switchInBattlerCounter = 0;
|
||||
gBattleStruct->eventsBeforeFirstTurnState++;
|
||||
break;
|
||||
case FIRST_TURN_EVENTS_MIRROR_HERB:
|
||||
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
|
||||
{
|
||||
if (ItemBattleEffects(ITEMEFFECT_MIRROR_HERB_FIRST_TURN, gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]))
|
||||
return;
|
||||
}
|
||||
gBattleStruct->switchInBattlerCounter = 0;
|
||||
gBattleStruct->eventsBeforeFirstTurnState++;
|
||||
break;
|
||||
case FIRST_TURN_EVENTS_EJECT_PACK:
|
||||
@ -3925,8 +3934,8 @@ static void TryDoEventsBeforeFirstTurn(void)
|
||||
gBattleStruct->appearedInBattle |= 1u << gBattlerPartyIndexes[i];
|
||||
}
|
||||
|
||||
*(&gBattleStruct->eventBlockCounter) = 0;
|
||||
*(&gBattleStruct->turnEffectsBattlerId) = 0;
|
||||
gBattleStruct->eventBlockCounter = 0;
|
||||
gBattleStruct->turnEffectsBattlerId = 0;
|
||||
gBattleScripting.moveendState = 0;
|
||||
gBattleStruct->faintedActionsState = 0;
|
||||
gBattleStruct->endTurnEventsCounter = 0;
|
||||
@ -5354,7 +5363,6 @@ static void CheckChangingTurnOrderEffects(void)
|
||||
gBattleMainFunc = RunTurnActionsFunctions;
|
||||
gBattleCommunication[3] = 0;
|
||||
gBattleCommunication[4] = 0;
|
||||
gBattleScripting.multihitMoveEffect = 0;
|
||||
gBattleResources->battleScriptsStack->size = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -352,7 +352,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
|
||||
[STRINGID_PKMNPROTECTEDBY] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was protected by {B_DEF_ABILITY}!"), //not in gen 5+, ability popup
|
||||
[STRINGID_PKMNPREVENTSUSAGE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents {B_ATK_NAME_WITH_PREFIX2} from using {B_CURRENT_MOVE}!"), //I don't see this in SV text
|
||||
[STRINGID_PKMNRESTOREDHPUSING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} restored HP using its {B_DEF_ABILITY}!"), //not in gen 5+, ability popup
|
||||
[STRINGID_PKMNCHANGEDTYPEWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} made it the {B_BUFF1} type!"), //not in gen 5+, ability popup
|
||||
[STRINGID_PKMNCHANGEDTYPEWITH] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s {B_EFF_ABILITY} made it the {B_BUFF1} type!"), //not in gen 5+, ability popup
|
||||
[STRINGID_PKMNPREVENTSROMANCEWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents romance!"), //not in gen 5+, ability popup
|
||||
[STRINGID_PKMNPREVENTSCONFUSIONWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents confusion!"), //not in gen 5+, ability popup
|
||||
[STRINGID_PKMNRAISEDFIREPOWERWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} raised the power of Fire-type moves!"), //not in gen 5+, ability popup
|
||||
|
||||
@ -962,6 +962,26 @@ static const struct PickupItem sPickupTable[] =
|
||||
|
||||
#undef _
|
||||
|
||||
static void ValidateSavedBattlerCounts(void)
|
||||
{
|
||||
if (gBattleStruct->savedAttackerCount > 0)
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!");
|
||||
// #endif
|
||||
}
|
||||
if (gBattleStruct->savedTargetCount > 0)
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
|
||||
static bool32 NoTargetPresent(u8 battler, u32 move)
|
||||
{
|
||||
if (!IsBattlerAlive(gBattlerTarget))
|
||||
@ -4005,6 +4025,10 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
|
||||
|
||||
static bool32 CanApplyAdditionalEffect(const struct AdditionalEffect *additionalEffect)
|
||||
{
|
||||
// If Toxic Chain will activate it blocks all other non volatile effects
|
||||
if (gBattleStruct->toxicChainPriority && additionalEffect->moveEffect <= MOVE_EFFECT_FROSTBITE)
|
||||
return FALSE;
|
||||
|
||||
if (additionalEffect->self
|
||||
&& NumAffectedSpreadMoveTargets() > 1
|
||||
&& GetNextTarget(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove), TRUE) != MAX_BATTLERS_COUNT)
|
||||
@ -4021,6 +4045,20 @@ static bool32 CanApplyAdditionalEffect(const struct AdditionalEffect *additional
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void SetToxicChainPriority(void)
|
||||
{
|
||||
if (gBattleStruct->toxicChainPriority)
|
||||
return;
|
||||
|
||||
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
|
||||
if (abilityAtk == ABILITY_TOXIC_CHAIN
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget, abilityAtk, GetBattlerAbility(gBattlerTarget))
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& RandomWeighted(RNG_TOXIC_CHAIN, 7, 3))
|
||||
gBattleStruct->toxicChainPriority = TRUE;
|
||||
}
|
||||
|
||||
static void Cmd_setadditionaleffects(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
@ -4028,6 +4066,7 @@ static void Cmd_setadditionaleffects(void)
|
||||
if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
{
|
||||
u32 numAdditionalEffects = GetMoveAdditionalEffectCount(gCurrentMove);
|
||||
SetToxicChainPriority();
|
||||
if (numAdditionalEffects > gBattleStruct->additionalEffectsCounter)
|
||||
{
|
||||
u32 percentChance;
|
||||
@ -4076,8 +4115,6 @@ static void Cmd_setadditionaleffects(void)
|
||||
gBattleScripting.moveEffect = 0;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
gBattleScripting.multihitMoveEffect = 0;
|
||||
}
|
||||
|
||||
static void Cmd_seteffectprimary(void)
|
||||
@ -4111,7 +4148,6 @@ static void Cmd_clearvolatile(void)
|
||||
gProtectStructs[battler].chargingTurn = FALSE;
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
gBattleScripting.multihitMoveEffect = 0;
|
||||
}
|
||||
|
||||
static void Cmd_tryfaintmon(void)
|
||||
@ -5849,8 +5885,9 @@ static void Cmd_moveend(void)
|
||||
{
|
||||
switch (gBattleScripting.moveendState)
|
||||
{
|
||||
case MOVEEND_SUM_DAMAGE: // Sum and store damage dealt for multi strike recoil
|
||||
case MOVEEND_SET_VALUES:
|
||||
gBattleScripting.savedDmg += gBattleStruct->moveDamage[gBattlerTarget];
|
||||
gBattleStruct->moveEndBattlerId = 0;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_PROTECT_LIKE_EFFECT:
|
||||
@ -6417,6 +6454,18 @@ static void Cmd_moveend(void)
|
||||
else
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_COLOR_CHANGE:
|
||||
while (gBattleStruct->moveEndBattlerId < gBattlersCount)
|
||||
{
|
||||
u32 battler = gBattleStruct->moveEndBattlerId++;
|
||||
if (battler == gBattlerAttacker)
|
||||
continue;
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_COLOR_CHANGE, battler, GetBattlerAbility(battler), 0, 0))
|
||||
return;
|
||||
}
|
||||
gBattleStruct->moveEndBattlerId = 0;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_RED_CARD:
|
||||
{
|
||||
u32 redCardBattlers = 0, i;
|
||||
@ -6648,10 +6697,24 @@ static void Cmd_moveend(void)
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_OPPORTUNIST:
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
|
||||
effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers
|
||||
else
|
||||
gBattleScripting.moveendState++;
|
||||
while (gBattleStruct->moveEndBattlerId < gBattlersCount)
|
||||
{
|
||||
u32 battler = gBattleStruct->moveEndBattlerId++;
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, GetBattlerAbility(battler), 0, 0))
|
||||
return;
|
||||
}
|
||||
gBattleStruct->moveEndBattlerId = 0;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_MIRROR_HERB:
|
||||
while (gBattleStruct->moveEndBattlerId < gBattlersCount)
|
||||
{
|
||||
u32 battler = gBattleStruct->moveEndBattlerId++;
|
||||
if (ItemBattleEffects(ITEMEFFECT_MIRROR_HERB, battler))
|
||||
return;
|
||||
}
|
||||
gBattleStruct->moveEndBattlerId = 0;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_PICKPOCKET:
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
@ -6782,25 +6845,7 @@ static void Cmd_moveend(void)
|
||||
&& gBattleMons[gBattlerAttacker].volatiles.lockConfusionTurns != 1) // And won't end this turn
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_IGNORE); // Cancel it
|
||||
|
||||
if (gBattleStruct->savedAttackerCount > 0)
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!");
|
||||
// #endif
|
||||
}
|
||||
if (gBattleStruct->savedTargetCount > 0)
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
// #endif
|
||||
}
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].volatiles.destinyBond > 0)
|
||||
gBattleMons[gBattlerAttacker].volatiles.destinyBond--;
|
||||
ValidateSavedBattlerCounts();
|
||||
gProtectStructs[gBattlerAttacker].shellTrap = FALSE;
|
||||
gBattleStruct->battlerState[gBattlerAttacker].ateBoost = FALSE;
|
||||
gSpecialStatuses[gBattlerAttacker].gemBoost = FALSE;
|
||||
@ -6814,12 +6859,15 @@ static void Cmd_moveend(void)
|
||||
gBattleStruct->fickleBeamBoosted = FALSE;
|
||||
gBattleStruct->battlerState[gBattlerAttacker].usedMicleBerry = FALSE;
|
||||
gBattleStruct->noTargetPresent = FALSE;
|
||||
gBattleStruct->toxicChainPriority = FALSE;
|
||||
if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
gBattleStruct->pledgeMove = FALSE;
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE)
|
||||
SetActiveGimmick(gBattlerAttacker, GIMMICK_NONE);
|
||||
if (B_CHARGE >= GEN_9 && moveType == TYPE_ELECTRIC && (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
gBattleMons[gBattlerAttacker].volatiles.charge = FALSE;
|
||||
if (gBattleMons[gBattlerAttacker].volatiles.destinyBond > 0)
|
||||
gBattleMons[gBattlerAttacker].volatiles.destinyBond--;
|
||||
// check if Stellar type boost should be used up
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA
|
||||
&& GetBattlerTeraType(gBattlerAttacker) == TYPE_STELLAR
|
||||
@ -7732,25 +7780,24 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler)
|
||||
|
||||
if (DoSwitchInAbilities(battler) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler))
|
||||
return TRUE;
|
||||
else if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0))
|
||||
return TRUE;
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (i == battler)
|
||||
continue;
|
||||
|
||||
switch (GetBattlerAbility(i))
|
||||
u32 ability = GetBattlerAbility(i);
|
||||
switch (ability)
|
||||
{
|
||||
case ABILITY_TRACE:
|
||||
case ABILITY_COMMANDER:
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, 0, 0, 0))
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, ability, 0, 0))
|
||||
return TRUE;
|
||||
break;
|
||||
case ABILITY_FORECAST:
|
||||
case ABILITY_FLOWER_GIFT:
|
||||
case ABILITY_PROTOSYNTHESIS:
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, i, 0, 0, 0))
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, i, ability, 0, 0))
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
@ -7758,6 +7805,17 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, i, GetBattlerAbility(i), 0, 0))
|
||||
return TRUE;
|
||||
}
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (ItemBattleEffects(ITEMEFFECT_MIRROR_HERB, battler))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (gBattlerByTurnOrder[i] == battler)
|
||||
@ -11988,8 +12046,9 @@ static void Cmd_jumpifnopursuitswitchdmg(void)
|
||||
|
||||
static void Cmd_tryrestorehpberry(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
if (TryRestoreHPBerries(gBattlerAttacker, ITEMEFFECT_TRY_HEALING))
|
||||
CMD_ARGS(u8 battler);
|
||||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
if (TryRestoreHPBerries(battler, ITEMEFFECT_TRY_HEALING))
|
||||
return;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
@ -910,7 +910,6 @@ void HandleAction_ActionFinished(void)
|
||||
gBattleScripting.moveendState = 0;
|
||||
gBattleCommunication[3] = 0;
|
||||
gBattleCommunication[4] = 0;
|
||||
gBattleScripting.multihitMoveEffect = 0;
|
||||
gBattleResources->battleScriptsStack->size = 0;
|
||||
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE;
|
||||
|
||||
@ -4727,6 +4726,48 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ABILITYEFFECT_COLOR_CHANGE:
|
||||
switch (gLastUsedAbility)
|
||||
{
|
||||
case ABILITY_COLOR_CHANGE:
|
||||
if (IsBattlerTurnDamaged(battler)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IS_BATTLER_OF_TYPE(battler, moveType)
|
||||
&& move != MOVE_STRUGGLE
|
||||
&& moveType != TYPE_STELLAR
|
||||
&& moveType != TYPE_MYSTERY)
|
||||
{
|
||||
gEffectBattler = gBattlerAbility = battler;
|
||||
SET_BATTLER_TYPE(battler, moveType);
|
||||
PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType);
|
||||
BattleScriptCall(BattleScript_ColorChangeActivates);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_BERSERK:
|
||||
if (IsBattlerTurnDamaged(battler)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& HadMoreThanHalfHpNowDoesnt(battler)
|
||||
&& CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
{
|
||||
gEffectBattler = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
||||
BattleScriptCall(BattleScript_BerserkActivates);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_ANGER_SHELL:
|
||||
if (IsBattlerTurnDamaged(battler)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& HadMoreThanHalfHpNowDoesnt(battler))
|
||||
{
|
||||
gEffectBattler = gBattlerAbility = battler;
|
||||
BattleScriptCall(BattleScript_AngerShellActivates);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ABILITYEFFECT_MOVE_END: // Think contact abilities.
|
||||
switch (gLastUsedAbility)
|
||||
{
|
||||
@ -4746,7 +4787,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& moveType == TYPE_DARK
|
||||
&& CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
{
|
||||
gEffectBattler = battler;
|
||||
gEffectBattler = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_ATK, 1, FALSE);
|
||||
BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet);
|
||||
effect++;
|
||||
@ -4758,7 +4799,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& (moveType == TYPE_DARK || moveType == TYPE_BUG || moveType == TYPE_GHOST)
|
||||
&& CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
{
|
||||
gEffectBattler = battler;
|
||||
gEffectBattler = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_SPEED, 1, FALSE);
|
||||
BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet);
|
||||
effect++;
|
||||
@ -4770,7 +4811,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& moveType == TYPE_WATER
|
||||
&& CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
{
|
||||
gEffectBattler = battler;
|
||||
gEffectBattler = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_DEF, 2, FALSE);
|
||||
BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet);
|
||||
effect++;
|
||||
@ -4782,26 +4823,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& IsBattlerAlive(battler)
|
||||
&& CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
{
|
||||
gEffectBattler = battler;
|
||||
gEffectBattler = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_DEF, 1, FALSE);
|
||||
BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_BERSERK:
|
||||
if (IsBattlerTurnDamaged(battler)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& HadMoreThanHalfHpNowDoesnt(battler)
|
||||
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
|
||||
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
|
||||
&& CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
{
|
||||
gEffectBattler = battler;
|
||||
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
||||
BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_WEAK_ARMOR:
|
||||
if (IsBattlerTurnDamaged(battler)
|
||||
&& IsBattlerAlive(battler)
|
||||
@ -4894,21 +4921,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_COLOR_CHANGE:
|
||||
if (move != MOVE_STRUGGLE
|
||||
&& !IsBattleMoveStatus(move)
|
||||
&& IsBattlerTurnDamaged(battler)
|
||||
&& !IS_BATTLER_OF_TYPE(battler, moveType)
|
||||
&& moveType != TYPE_STELLAR
|
||||
&& moveType != TYPE_MYSTERY
|
||||
&& IsBattlerAlive(battler))
|
||||
{
|
||||
SET_BATTLER_TYPE(battler, moveType);
|
||||
PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType);
|
||||
BattleScriptCall(BattleScript_ColorChangeActivates);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_GOOEY:
|
||||
case ABILITY_TANGLING_HAIR:
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
@ -5123,7 +5135,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)
|
||||
&& (moveType == TYPE_FIRE || moveType == TYPE_WATER))
|
||||
{
|
||||
gEffectBattler = battler;
|
||||
gEffectBattler = gBattlerAbility = battler;
|
||||
SET_STATCHANGER(STAT_SPEED, 6, FALSE);
|
||||
BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet);
|
||||
effect++;
|
||||
@ -5209,24 +5221,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)
|
||||
&& moveType == TYPE_FIRE)
|
||||
{
|
||||
gEffectBattler = gBattlerTarget;
|
||||
gEffectBattler = gBattlerAbility = gBattlerTarget;
|
||||
SET_STATCHANGER(STAT_ATK, 1, FALSE);
|
||||
BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_ANGER_SHELL:
|
||||
if (!gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1) // Activates after all hits from a multi-hit move.
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& HadMoreThanHalfHpNowDoesnt(gBattlerTarget)
|
||||
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)))
|
||||
{
|
||||
BattleScriptCall(BattleScript_AngerShellActivates);
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_WIND_POWER:
|
||||
if (!IsWindMove(gCurrentMove))
|
||||
break;
|
||||
@ -5274,13 +5274,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
}
|
||||
break;
|
||||
case ABILITY_TOXIC_CHAIN:
|
||||
if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget, gLastUsedAbility, GetBattlerAbility(gBattlerTarget))
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget) // Need to actually hit the target
|
||||
&& RandomWeighted(RNG_TOXIC_CHAIN, 7, 3))
|
||||
if (gBattleStruct->toxicChainPriority)
|
||||
{
|
||||
gBattleStruct->toxicChainPriority = FALSE;
|
||||
gEffectBattler = gBattlerTarget;
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_TOXIC;
|
||||
@ -5356,25 +5352,22 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
}
|
||||
break;
|
||||
case ABILITYEFFECT_OPPORTUNIST:
|
||||
/* Similar to ABILITYEFFECT_IMMUNITY in that it loops through all battlers.
|
||||
* Is called after ABILITYEFFECT_ON_SWITCHIN to copy any boosts
|
||||
* from switch in abilities e.g. intrepid sword, as
|
||||
*/
|
||||
for (battler = 0; battler < gBattlersCount; battler++)
|
||||
case ABILITYEFFECT_OPPORTUNIST_FIRST_TURN:
|
||||
switch (ability)
|
||||
{
|
||||
switch (GetBattlerAbility(battler))
|
||||
case ABILITY_OPPORTUNIST:
|
||||
if (gProtectStructs[battler].activateOpportunist == 2)
|
||||
{
|
||||
case ABILITY_OPPORTUNIST:
|
||||
if (gProtectStructs[battler].activateOpportunist == 2)
|
||||
{
|
||||
gBattleScripting.battler = battler;
|
||||
gProtectStructs[battler].activateOpportunist--;
|
||||
ChooseStatBoostAnimation(battler);
|
||||
BattleScriptPushCursorAndCallback(BattleScript_OpportunistCopyStatChange);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
gBattleScripting.battler = battler;
|
||||
gProtectStructs[battler].activateOpportunist--;
|
||||
ChooseStatBoostAnimation(battler);
|
||||
if (caseID == ABILITYEFFECT_OPPORTUNIST_FIRST_TURN)
|
||||
BattleScriptPushCursorAndCallback(BattleScript_OpportunistCopyStatChangeEnd3);
|
||||
else
|
||||
BattleScriptCall(BattleScript_OpportunistCopyStatChange);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ABILITYEFFECT_IMMUNITY:
|
||||
@ -6527,7 +6520,7 @@ static u32 TryConsumeMirrorHerb(u32 battler, enum ItemCaseId caseID)
|
||||
gBattleScripting.battler = battler;
|
||||
gProtectStructs[battler].eatMirrorHerb = 0;
|
||||
ChooseStatBoostAnimation(battler);
|
||||
if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL)
|
||||
if (caseID == ITEMEFFECT_MIRROR_HERB_FIRST_TURN)
|
||||
BattleScriptExecute(BattleScript_MirrorHerbCopyStatChangeEnd2);
|
||||
else
|
||||
BattleScriptCall(BattleScript_MirrorHerbCopyStatChange);
|
||||
@ -6767,9 +6760,6 @@ static u8 ItemEffectMoveEnd(u32 battler, enum ItemHoldEffect holdEffect)
|
||||
case HOLD_EFFECT_BERSERK_GENE:
|
||||
effect = ConsumeBerserkGene(battler, ITEMEFFECT_NONE);
|
||||
break;
|
||||
case HOLD_EFFECT_MIRROR_HERB:
|
||||
effect = TryConsumeMirrorHerb(battler, ITEMEFFECT_NONE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -6832,6 +6822,43 @@ static inline bool32 TryCureStatus(u32 battler, enum ItemCaseId caseId)
|
||||
return effect;
|
||||
}
|
||||
|
||||
// This is hacky and could potentially be improved because ideally this function wouldn't exist but there is some inconsitency with timings.
|
||||
static bool32 ShouldWaitWithActivation(u32 battler, enum ItemHoldEffect holdEffect)
|
||||
{
|
||||
if (holdEffect != HOLD_EFFECT_RESTORE_HP
|
||||
&& holdEffect != HOLD_EFFECT_RESTORE_PCT_HP
|
||||
&& holdEffect != HOLD_EFFECT_RESTORE_PP
|
||||
&& holdEffect != HOLD_EFFECT_CONFUSE_SPICY
|
||||
&& holdEffect != HOLD_EFFECT_CONFUSE_DRY
|
||||
&& holdEffect != HOLD_EFFECT_CONFUSE_SWEET
|
||||
&& holdEffect != HOLD_EFFECT_CONFUSE_BITTER
|
||||
&& holdEffect != HOLD_EFFECT_CONFUSE_SOUR)
|
||||
return FALSE;
|
||||
|
||||
// Restore HP berries can be knocked off
|
||||
if (gBattleStruct->battlerState[battler].itemCanBeKnockedOff)
|
||||
return TRUE;
|
||||
|
||||
if (IsBattlerTurnDamaged(battler)
|
||||
&& gMultiHitCounter == 0 // Non multi hit moves don't wait for Berserk / Anger Shell activation
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !TestIfSheerForceAffected(battler, gCurrentMove)
|
||||
&& HadMoreThanHalfHpNowDoesnt(battler))
|
||||
{
|
||||
switch (GetBattlerAbility(battler))
|
||||
{
|
||||
case ABILITY_BERSERK:
|
||||
return CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN);
|
||||
case ABILITY_ANGER_SHELL:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
|
||||
{
|
||||
u32 moveType = 0;
|
||||
@ -7037,9 +7064,6 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
|
||||
case HOLD_EFFECT_BERSERK_GENE:
|
||||
effect = ConsumeBerserkGene(battler, caseID);
|
||||
break;
|
||||
case HOLD_EFFECT_MIRROR_HERB:
|
||||
effect = TryConsumeMirrorHerb(battler, caseID);
|
||||
break;
|
||||
case HOLD_EFFECT_BOOSTER_ENERGY:
|
||||
effect = TryBoosterEnergy(battler, GetBattlerAbility(battler), caseID);
|
||||
break;
|
||||
@ -7058,9 +7082,48 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ITEMEFFECT_LEFTOVERS:
|
||||
switch (battlerHoldEffect)
|
||||
{
|
||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON))
|
||||
{
|
||||
goto LEFTOVERS;
|
||||
}
|
||||
else if (!IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
|
||||
{
|
||||
gBattleScripting.battler = battler;
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8;
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
gBattleStruct->moveDamage[battler] = 1;
|
||||
BattleScriptExecute(BattleScript_ItemHurtEnd2);
|
||||
effect = ITEM_HP_CHANGE;
|
||||
RecordItemEffectBattle(battler, battlerHoldEffect);
|
||||
PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem);
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_LEFTOVERS:
|
||||
LEFTOVERS:
|
||||
if (gBattleMons[battler].hp < gBattleMons[battler].maxHP
|
||||
&& (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock))
|
||||
{
|
||||
gBattleScripting.battler = battler;
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16;
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
gBattleStruct->moveDamage[battler] = 1;
|
||||
gBattleStruct->moveDamage[battler] *= -1;
|
||||
BattleScriptExecute(BattleScript_ItemHealHP_End2);
|
||||
effect = ITEM_HP_CHANGE;
|
||||
RecordItemEffectBattle(battler, battlerHoldEffect);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ITEMEFFECT_NORMAL:
|
||||
case ITEMEFFECT_TRY_HEALING:
|
||||
if (gBattleMons[battler].hp)
|
||||
if (IsBattlerAlive(battler))
|
||||
{
|
||||
switch (battlerHoldEffect)
|
||||
{
|
||||
@ -7073,35 +7136,10 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
|
||||
case HOLD_EFFECT_RESTORE_PP:
|
||||
effect = ItemRestorePp(battler, gLastUsedItem, caseID);
|
||||
break;
|
||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON))
|
||||
{
|
||||
goto LEFTOVERS;
|
||||
}
|
||||
else if (!IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
|
||||
{
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8;
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
gBattleStruct->moveDamage[battler] = 1;
|
||||
BattleScriptExecute(BattleScript_ItemHurtEnd2);
|
||||
effect = ITEM_HP_CHANGE;
|
||||
RecordItemEffectBattle(battler, battlerHoldEffect);
|
||||
PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem);
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_LEFTOVERS:
|
||||
LEFTOVERS:
|
||||
if (gBattleMons[battler].hp < gBattleMons[battler].maxHP
|
||||
&& (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock))
|
||||
{
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16;
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
gBattleStruct->moveDamage[battler] = 1;
|
||||
gBattleStruct->moveDamage[battler] *= -1;
|
||||
BattleScriptExecute(BattleScript_ItemHealHP_End2);
|
||||
effect = ITEM_HP_CHANGE;
|
||||
RecordItemEffectBattle(battler, battlerHoldEffect);
|
||||
}
|
||||
case HOLD_EFFECT_WHITE_HERB:
|
||||
effect = RestoreWhiteHerbStats(battler);
|
||||
if (effect != 0)
|
||||
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
|
||||
break;
|
||||
case HOLD_EFFECT_CONFUSE_SPICY:
|
||||
effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SPICY, caseID);
|
||||
@ -7220,9 +7258,6 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
|
||||
case HOLD_EFFECT_BERSERK_GENE:
|
||||
effect = ConsumeBerserkGene(battler, caseID);
|
||||
break;
|
||||
case HOLD_EFFECT_MIRROR_HERB:
|
||||
effect = TryConsumeMirrorHerb(battler, caseID);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -7255,14 +7290,12 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
|
||||
case ITEMEFFECT_MOVE_END:
|
||||
for (battler = 0; battler < gBattlersCount; battler++)
|
||||
{
|
||||
// If item can be knocked off berry activation will be blocked, but not other items
|
||||
if (gBattleStruct->battlerState[battler].itemCanBeKnockedOff
|
||||
&& (GetItemPocket(gBattleMons[battler].item) == POCKET_BERRIES
|
||||
|| GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_RESTORE_HP))
|
||||
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE);
|
||||
if (ShouldWaitWithActivation(battler, holdEffect))
|
||||
continue;
|
||||
|
||||
gLastUsedItem = gBattleMons[battler].item;
|
||||
effect = ItemEffectMoveEnd(battler, GetBattlerHoldEffect(battler, TRUE));
|
||||
effect = ItemEffectMoveEnd(battler, holdEffect);
|
||||
if (effect)
|
||||
{
|
||||
gPotentialItemEffectBattler = gBattleScripting.battler = battler;
|
||||
@ -7594,6 +7627,17 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ITEMEFFECT_MIRROR_HERB:
|
||||
case ITEMEFFECT_MIRROR_HERB_FIRST_TURN:
|
||||
switch (battlerHoldEffect)
|
||||
{
|
||||
case HOLD_EFFECT_MIRROR_HERB:
|
||||
effect = TryConsumeMirrorHerb(battler, caseID);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Berry was successfully used on a Pokemon.
|
||||
|
||||
@ -93,3 +93,23 @@ SINGLE_BATTLE_TEST("Anger Shell activates after all hits from a multi-hit move")
|
||||
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Anger Shell does not activate if move is boosted by Sheer Force")
|
||||
{
|
||||
u16 maxHp = 500;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KLAWF) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); }
|
||||
OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_EMBER); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent);
|
||||
NOT ABILITY_POPUP(player, ABILITY_ANGER_SHELL);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,3 +73,64 @@ SINGLE_BATTLE_TEST("Berserk activates after all hits from a multi-hit move")
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Berserk does not activate if move is boosted by Sheer Force")
|
||||
{
|
||||
u16 maxHp = 500;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(maxHp / 2 + 1); }
|
||||
OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_EMBER); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent);
|
||||
NOT ABILITY_POPUP(player, ABILITY_BERSERK);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Berserk will not activate if the last multi hit move activates a restore berry")
|
||||
{
|
||||
u32 j;
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_DOUBLE_SLAP) == EFFECT_MULTI_HIT);
|
||||
PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); Item(ITEM_SITRUS_BERRY); MaxHP(100); HP(90); }
|
||||
OPPONENT(SPECIES_SHELLDER) { Ability(ABILITY_SKILL_LINK); } // Always hits 5 times.
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_DOUBLE_SLAP); }
|
||||
} SCENE {
|
||||
for (j = 0; j < 4; j++) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SLAP, opponent);
|
||||
NOT ABILITY_POPUP(player, ABILITY_BERSERK);
|
||||
}
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SLAP, opponent);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
NOT ABILITY_POPUP(player, ABILITY_BERSERK);
|
||||
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Berserk activates before the hp can be restored on non multi hit moves")
|
||||
{
|
||||
u16 maxHp = 500;
|
||||
GIVEN {
|
||||
ASSUME(!IsBattleMoveStatus(MOVE_SCRATCH));
|
||||
PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); Item(ITEM_SITRUS_BERRY); MaxHP(maxHp); HP(maxHp / 2 + 1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
|
||||
ABILITY_POPUP(player, ABILITY_BERSERK);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,3 +153,16 @@ SINGLE_BATTLE_TEST("Color Change changes the type to Normal when a Pokemon is hi
|
||||
MESSAGE("The opposing Kecleon's Color Change made it the Normal type!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Color Change does not activate if move is boosted by Sheer Force")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KECLEON) { Ability(ABILITY_COLOR_CHANGE); }
|
||||
OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_EMBER); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent);
|
||||
NOT ABILITY_POPUP(player, ABILITY_COLOR_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,3 +294,24 @@ SINGLE_BATTLE_TEST("Opportunist and Mirror Herb stack stat increases")
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Opportunist and Mirror Herb resolve correctly")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
|
||||
PLAYER(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
OPPONENT(SPECIES_MEOWSCARADA) { Item(ITEM_MIRROR_HERB); }
|
||||
OPPONENT(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); Item(ITEM_MIRROR_HERB); }
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_INTREPID_SWORD);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_OPPORTUNIST);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
|
||||
} THEN {
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user