Adds some Snatch interactions, fixes for Dragon Darts, Trace, Primal Reversion, Protosynthesis/Quark Drive (#5430)
* Fixes Electrified Dragon Darts sometimes targeting battlers with absorbing abilities (Volt Absorb, Motor Drive) * Add Snatch interactions with Dancer, Swallow * Trace fix + cleanup * Simplify Quash * Fixes multiple mons with Primal Reversion causing only one Primal Reversion, add tests * Fix Booster Energy Ability Popup * Accidentally removed healing from Swallow * More Trace cleanup
This commit is contained in:
parent
55086586c5
commit
e67d5a23ed
10 changed files with 313 additions and 55 deletions
|
@ -6961,12 +6961,12 @@ BattleScript_WishMegaEvolution::
|
|||
|
||||
BattleScript_PrimalReversion::
|
||||
call BattleScript_PrimalReversionRet
|
||||
end2
|
||||
end3
|
||||
|
||||
BattleScript_PrimalReversionRestoreAttacker::
|
||||
call BattleScript_PrimalReversionRet
|
||||
copybyte gBattlerAttacker, sSAVED_BATTLER
|
||||
end2
|
||||
end3
|
||||
|
||||
BattleScript_PrimalReversionRet::
|
||||
flushtextbox
|
||||
|
@ -7675,15 +7675,11 @@ BattleScript_EmergencyExitWildNoPopUp::
|
|||
|
||||
BattleScript_TraceActivates::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
call BattleScript_AbilityPopUp
|
||||
call BattleScript_AbilityPopUpScripting
|
||||
printstring STRINGID_PKMNTRACED
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
settracedability BS_SCRIPTING
|
||||
switchinabilities BS_SCRIPTING
|
||||
return
|
||||
|
||||
BattleScript_TraceActivatesEnd3::
|
||||
call BattleScript_TraceActivates
|
||||
end3
|
||||
|
||||
BattleScript_ReceiverActivates::
|
||||
|
@ -10011,7 +10007,7 @@ BattleScript_BerserkGeneRet_End:
|
|||
|
||||
BattleScript_BoosterEnergyEnd2::
|
||||
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1
|
||||
call BattleScript_AbilityPopUpTarget
|
||||
call BattleScript_AbilityPopUpScripting
|
||||
printstring STRINGID_BOOSTERENERGYACTIVATES
|
||||
waitmessage B_WAIT_TIME_MED
|
||||
printstring STRINGID_STATWASHEIGHTENED
|
||||
|
|
|
@ -93,7 +93,7 @@ struct ResourceFlags
|
|||
#define RESOURCE_FLAG_ROOST 0x2
|
||||
#define RESOURCE_FLAG_UNBURDEN 0x4
|
||||
#define RESOURCE_FLAG_UNUSED 0x8
|
||||
#define RESOURCE_FLAG_TRACED 0x10
|
||||
#define RESOURCE_FLAG_UNUSED_2 0x10
|
||||
#define RESOURCE_FLAG_EMERGENCY_EXIT 0x20
|
||||
#define RESOURCE_FLAG_NEUTRALIZING_GAS 0x40
|
||||
#define RESOURCE_FLAG_ICE_FACE 0x80
|
||||
|
@ -751,6 +751,7 @@ struct BattleStruct
|
|||
u8 blunderPolicy:1; // should blunder policy activate
|
||||
u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
|
||||
u8 bouncedMoveIsUsed:1;
|
||||
u8 snatchedMoveIsUsed:1;
|
||||
u8 descriptionSubmenu:1; // For Move Description window in move selection screen
|
||||
u8 ackBallUseBtn:1; // Used for the last used ball feature
|
||||
u8 ballSwapped:1; // Used for the last used ball feature
|
||||
|
|
|
@ -166,7 +166,6 @@ extern const u8 BattleScript_ItemSteal[];
|
|||
extern const u8 BattleScript_DrizzleActivates[];
|
||||
extern const u8 BattleScript_SpeedBoostActivates[];
|
||||
extern const u8 BattleScript_TraceActivates[];
|
||||
extern const u8 BattleScript_TraceActivatesEnd3[];
|
||||
extern const u8 BattleScript_RainDishActivates[];
|
||||
extern const u8 BattleScript_SandstreamActivates[];
|
||||
extern const u8 BattleScript_ShedSkinActivates[];
|
||||
|
|
|
@ -256,7 +256,7 @@ bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect);
|
|||
bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument);
|
||||
bool32 MoveHasChargeTurnAdditionalEffect(u32 move);
|
||||
bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 TargetFullyImmuneToCurrMove(u32 BattlerAtk, u32 battlerDef);
|
||||
bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef);
|
||||
|
||||
bool32 CanBeSlept(u32 battler, u32 ability);
|
||||
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
|
|
|
@ -1401,6 +1401,7 @@ static void Cmd_attackcanceler(void)
|
|||
if ((gProtectStructs[gBattlerByTurnOrder[i]].stealMove) && gMovesInfo[gCurrentMove].snatchAffected)
|
||||
{
|
||||
gProtectStructs[gBattlerByTurnOrder[i]].stealMove = FALSE;
|
||||
gBattleStruct->snatchedMoveIsUsed = TRUE;
|
||||
gBattleScripting.battler = gBattlerByTurnOrder[i];
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_SnatchedMove;
|
||||
|
@ -6287,7 +6288,7 @@ static void Cmd_moveend(void)
|
|||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_DANCER: // Special case because it's so annoying
|
||||
if (gMovesInfo[gCurrentMove].danceMove)
|
||||
if (gMovesInfo[gCurrentMove].danceMove && !gBattleStruct->snatchedMoveIsUsed)
|
||||
{
|
||||
u32 battler, nextDancer = 0;
|
||||
bool32 hasDancerTriggered = FALSE;
|
||||
|
@ -6431,6 +6432,7 @@ static void Cmd_moveend(void)
|
|||
gBattleStruct->swapDamageCategory = FALSE;
|
||||
gBattleStruct->categoryOverride = FALSE;
|
||||
gBattleStruct->bouncedMoveIsUsed = FALSE;
|
||||
gBattleStruct->snatchedMoveIsUsed = FALSE;
|
||||
gBattleStruct->enduredDamage = 0;
|
||||
gBattleStruct->additionalEffectsCounter = 0;
|
||||
gBattleStruct->poisonPuppeteerConfusion = FALSE;
|
||||
|
@ -11537,7 +11539,7 @@ static void Cmd_stockpiletohpheal(void)
|
|||
|
||||
const u8 *failInstr = cmd->failInstr;
|
||||
|
||||
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0)
|
||||
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0 && !gBattleStruct->snatchedMoveIsUsed)
|
||||
{
|
||||
gBattlescriptCurrInstr = failInstr;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FAILED;
|
||||
|
@ -11552,15 +11554,23 @@ static void Cmd_stockpiletohpheal(void)
|
|||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FULL_HP;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gDisableStructs[gBattlerAttacker].stockpileCounter > 0)
|
||||
{
|
||||
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter));
|
||||
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
||||
gBattleStruct->moveEffect2 = MOVE_EFFECT_STOCKPILE_WORE_OFF;
|
||||
}
|
||||
else // Snatched move
|
||||
{
|
||||
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
|
||||
gBattleScripting.animTurn = 1;
|
||||
}
|
||||
|
||||
if (gBattleMoveDamage == 0)
|
||||
gBattleMoveDamage = 1;
|
||||
gBattleMoveDamage *= -1;
|
||||
|
||||
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
||||
gBattleStruct->moveEffect2 = MOVE_EFFECT_STOCKPILE_WORE_OFF;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
}
|
||||
|
@ -17123,29 +17133,17 @@ void BS_TryQuash(void)
|
|||
// If the above condition is not true, it means we are faster than the foe, so we can set the quash bit
|
||||
gProtectStructs[gBattlerTarget].quash = TRUE;
|
||||
|
||||
if (B_QUASH_TURN_ORDER < GEN_8)
|
||||
{
|
||||
// Gen 7- config makes target go last so that the order of quash targets is kept for the correct turn order
|
||||
j = GetBattlerTurnOrderNum(gBattlerTarget);
|
||||
for (i = j + 1; i < gBattlersCount; i++)
|
||||
{
|
||||
SwapTurnOrder(i, j);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gen 8+ config only alters Turn Order of battlers affected by Quash, dynamic speed should handle the rest
|
||||
for (i = gCurrentTurnActionNumber + 1; i < gBattlersCount - 1; i++)
|
||||
{
|
||||
// this implementation assumes turn order is correct when using Quash
|
||||
i = GetBattlerTurnOrderNum(gBattlerTarget);
|
||||
for (j = i + 1; j < gBattlersCount; j++)
|
||||
{
|
||||
u32 battler1 = gBattlerByTurnOrder[i], battler2 = gBattlerByTurnOrder[j];
|
||||
if ((gProtectStructs[battler1].quash || gProtectStructs[battler2].quash)
|
||||
&& GetWhichBattlerFaster(battler1, battler2, FALSE) == -1)
|
||||
// Gen 7- config makes target go last so that the order of quash targets is kept for the correct turn order
|
||||
// Gen 8+ config alters Turn Order of the target according to speed, dynamic speed should handle the rest
|
||||
if (B_QUASH_TURN_ORDER < GEN_8 || GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1)
|
||||
SwapTurnOrder(i, j);
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
|
|
@ -4368,13 +4368,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
|||
|
||||
if (gSpecialStatuses[battler].switchInAbilityDone)
|
||||
break;
|
||||
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_TRACED)
|
||||
break;
|
||||
|
||||
side = (BATTLE_OPPOSITE(GetBattlerPosition(battler))) & BIT_SIDE;
|
||||
target1 = GetBattlerAtPosition(side);
|
||||
target2 = GetBattlerAtPosition(side + BIT_FLANK);
|
||||
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
{
|
||||
if (!gAbilitiesInfo[gBattleMons[target1].ability].cantBeTraced && gBattleMons[target1].hp != 0
|
||||
|
@ -4393,11 +4390,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
|||
|
||||
if (effect != 0)
|
||||
{
|
||||
BattleScriptPushCursorAndCallback(BattleScript_TraceActivatesEnd3);
|
||||
gBattleResources->flags->flags[battler] &= ~RESOURCE_FLAG_TRACED;
|
||||
BattleScriptPushCursorAndCallback(BattleScript_TraceActivates);
|
||||
gBattleStruct->tracedAbility[battler] = gLastUsedAbility = gBattleMons[chosenTarget].ability;
|
||||
RecordAbilityBattle(chosenTarget, gLastUsedAbility); // Record the opposing battler has this ability
|
||||
battler = gBattlerAbility = gBattleScripting.battler = battler;
|
||||
gBattlerAbility = battler;
|
||||
|
||||
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, chosenTarget, gBattlerPartyIndexes[chosenTarget])
|
||||
PREPARE_ABILITY_BUFFER(gBattleTextBuff2, gLastUsedAbility)
|
||||
|
@ -5214,7 +5210,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
|||
break;
|
||||
case ABILITY_GOOD_AS_GOLD:
|
||||
if (IS_MOVE_STATUS(gCurrentMove)
|
||||
&& !(moveTarget & MOVE_TARGET_USER)
|
||||
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
|
||||
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
|
||||
effect = 3;
|
||||
|
@ -6388,14 +6383,14 @@ bool32 TryPrimalReversion(u32 battler)
|
|||
{
|
||||
if (gBattlerAttacker == battler)
|
||||
{
|
||||
BattleScriptExecute(BattleScript_PrimalReversion);
|
||||
BattleScriptPushCursorAndCallback(BattleScript_PrimalReversion);
|
||||
}
|
||||
else
|
||||
{
|
||||
// edge case for scenarios like a switch-in after activated eject button
|
||||
gBattleScripting.savedBattler = gBattlerAttacker;
|
||||
gBattlerAttacker = battler;
|
||||
BattleScriptExecute(BattleScript_PrimalReversionRestoreAttacker);
|
||||
BattleScriptPushCursorAndCallback(BattleScript_PrimalReversionRestoreAttacker);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -8706,7 +8701,7 @@ u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc)
|
|||
|
||||
u32 GetMoveTargetCount(u32 move, u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
switch (GetBattlerMoveTargetType(gBattlerAttacker, move))
|
||||
switch (GetBattlerMoveTargetType(battlerAtk, move))
|
||||
{
|
||||
case MOVE_TARGET_BOTH:
|
||||
return !(gAbsentBattlerFlags & gBitTable[battlerDef])
|
||||
|
@ -11816,19 +11811,19 @@ bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef)
|
|||
&& battlerDef != BATTLE_PARTNER(battlerAtk));
|
||||
}
|
||||
|
||||
static inline bool32 DoesCurrentTargetHaveAbilityImmunity(void)
|
||||
static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerDef)
|
||||
{
|
||||
return (AbilityBattleEffects(ABILITYEFFECT_WOULD_BLOCK, gBattlerTarget, 0, 0, 0)
|
||||
|| AbilityBattleEffects(ABILITYEFFECT_WOULD_ABSORB, gBattlerTarget, 0, 0, 0));
|
||||
return (AbilityBattleEffects(ABILITYEFFECT_WOULD_BLOCK, battlerDef, 0, 0, 0)
|
||||
|| AbilityBattleEffects(ABILITYEFFECT_WOULD_ABSORB, battlerDef, 0, 0, 0));
|
||||
}
|
||||
|
||||
bool32 TargetFullyImmuneToCurrMove(u32 BattlerAtk, u32 battlerDef)
|
||||
bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
u32 moveType = 0;
|
||||
GET_MOVE_TYPE(gCurrentMove, moveType);
|
||||
|
||||
return ((CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, BattlerAtk, battlerDef, GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0))
|
||||
|| IsBattlerProtected(BattlerAtk, battlerDef, gCurrentMove)
|
||||
return ((CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0))
|
||||
|| IsBattlerProtected(battlerAtk, battlerDef, gCurrentMove)
|
||||
|| IsSemiInvulnerable(battlerDef, gCurrentMove)
|
||||
|| DoesCurrentTargetHaveAbilityImmunity());
|
||||
|| DoesBattlerHaveAbilityImmunity(battlerDef));
|
||||
}
|
||||
|
|
|
@ -146,6 +146,85 @@ SINGLE_BATTLE_TEST("Dancer-called attacks have their type updated")
|
|||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dancer doesn't trigger on a snatched move")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE);
|
||||
ASSUME(gMovesInfo[MOVE_SNATCH].effect == EFFECT_SNATCH);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_ORICORIO);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_SNATCH); MOVE(playerRight, MOVE_DRAGON_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNATCH, opponentRight);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dancer triggers on Instructed dance moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE);
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].instructBanned == FALSE);
|
||||
ASSUME(gMovesInfo[MOVE_INSTRUCT].effect == EFFECT_INSTRUCT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_ORICORIO);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_DRAGON_DANCE); MOVE(playerLeft, MOVE_INSTRUCT, target: playerRight); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dancer-called move doesn't update move to be Instructed")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE);
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].instructBanned == FALSE);
|
||||
ASSUME(gMovesInfo[MOVE_INSTRUCT].effect == EFFECT_INSTRUCT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_ORICORIO);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_TACKLE, target: playerLeft); MOVE(playerRight, MOVE_DRAGON_DANCE); MOVE(opponentRight, MOVE_INSTRUCT, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, opponentRight);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
}
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dancer doesn't call a move that didn't execute due to Powder")
|
||||
{
|
||||
GIVEN {
|
||||
|
|
|
@ -80,6 +80,21 @@ SINGLE_BATTLE_TEST("Trace will copy an opponent's ability whenever it has the ch
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
SINGLE_BATTLE_TEST("Trace copies opponent's Intimidate and triggers it immediately")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_RALTS) { Ability(ABILITY_TRACE); }
|
||||
OPPONENT(SPECIES_MASQUERAIN) { Ability(ABILITY_INTIMIDATE); }
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_TRACE);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Trace respects the turn order")
|
||||
{
|
||||
GIVEN {
|
||||
|
|
|
@ -234,3 +234,101 @@ SINGLE_BATTLE_TEST("Primal reversion happens immediately if it was brought in by
|
|||
EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DOUBLE_BATTLE_TEST("Primal reversion triggers for multiple battlers if multiple fainted the previous turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_CATERPIE) { HP(1); }
|
||||
PLAYER(SPECIES_RESHIRAM);
|
||||
OPPONENT(SPECIES_CATERPIE) { HP(1); }
|
||||
OPPONENT(SPECIES_CATERPIE) { HP(1); }
|
||||
OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); }
|
||||
OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_EARTHQUAKE);
|
||||
SEND_OUT(opponentRight, 3);
|
||||
SEND_OUT(opponentLeft, 2);
|
||||
SEND_OUT(playerRight, 2); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, playerLeft);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_PRIMORDIAL_SEA);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_DESOLATE_LAND);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Primal reversion triggers for all battlers if multiple fainted the previous turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].target == MOVE_TARGET_FOES_AND_ALLY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_CATERPIE) { HP(1); }
|
||||
PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); }
|
||||
PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
|
||||
OPPONENT(SPECIES_CATERPIE) { HP(1); }
|
||||
OPPONENT(SPECIES_CATERPIE) { HP(1); }
|
||||
OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); }
|
||||
OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_EXPLOSION);
|
||||
SEND_OUT(opponentRight, 3);
|
||||
SEND_OUT(opponentLeft, 2);
|
||||
SEND_OUT(playerRight, 3);
|
||||
SEND_OUT(playerLeft, 2); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_PRIMORDIAL_SEA);
|
||||
ABILITY_POPUP(playerRight, ABILITY_DESOLATE_LAND);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_PRIMORDIAL_SEA);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_DESOLATE_LAND);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Primal reversion and other switch-in effects trigger for all battlers if multiple fainted the previous turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].target == MOVE_TARGET_FOES_AND_ALLY);
|
||||
ASSUME(gMovesInfo[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB);
|
||||
ASSUME(gMovesInfo[MOVE_SPIKES].effect == EFFECT_SPIKES);
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC_SPIKES].effect == EFFECT_TOXIC_SPIKES);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_CATERPIE) { HP(1); }
|
||||
PLAYER(SPECIES_SCRAFTY) { Ability(ABILITY_INTIMIDATE); }
|
||||
PLAYER(SPECIES_RESHIRAM);
|
||||
OPPONENT(SPECIES_CATERPIE) { HP(1); }
|
||||
OPPONENT(SPECIES_CATERPIE) { HP(1); }
|
||||
OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); }
|
||||
OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_STICKY_WEB);
|
||||
MOVE(opponentLeft, MOVE_SPIKES);
|
||||
MOVE(playerRight, MOVE_TOXIC_SPIKES); }
|
||||
TURN { MOVE(playerLeft, MOVE_EXPLOSION);
|
||||
SEND_OUT(opponentRight, 3);
|
||||
SEND_OUT(opponentLeft, 2);
|
||||
SEND_OUT(playerRight, 3);
|
||||
SEND_OUT(playerLeft, 2); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(playerRight, ABILITY_TURBOBLAZE);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_PRIMORDIAL_SEA);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_DESOLATE_LAND);
|
||||
} THEN {
|
||||
EXPECT_NE(playerLeft->hp, playerLeft->maxHP);
|
||||
EXPECT_NE(playerRight->hp, playerRight->maxHP);
|
||||
EXPECT_EQ(opponentLeft->status1, STATUS1_POISON);
|
||||
EXPECT_EQ(opponentRight->status1, STATUS1_POISON);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,6 +94,83 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes the left ally twice if the target is a
|
|||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts strikes left ally twice if electrified and right ally has Volt Absorb")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_LANTURN) { Ability(ABILITY_VOLT_ABSORB); };
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
MESSAGE("Hit 2 time(s)!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts strikes right ally twice if electrified and left ally has Volt Absorb")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_LANTURN) { Ability(ABILITY_VOLT_ABSORB); };
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
MESSAGE("Hit 2 time(s)!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts strikes left ally twice if electrified and right ally has Motor Drive")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ELECTIVIRE) { Ability(ABILITY_MOTOR_DRIVE); };
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
MESSAGE("Hit 2 time(s)!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts strikes right ally twice if electrified and left ally has Motor Drive")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ELECTIVIRE) { Ability(ABILITY_MOTOR_DRIVE); };
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
MESSAGE("Hit 2 time(s)!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts strikes the ally twice if the target is in a semi-invulnerable turn")
|
||||
{
|
||||
GIVEN {
|
||||
|
|
Loading…
Reference in a new issue