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::
|
BattleScript_PrimalReversion::
|
||||||
call BattleScript_PrimalReversionRet
|
call BattleScript_PrimalReversionRet
|
||||||
end2
|
end3
|
||||||
|
|
||||||
BattleScript_PrimalReversionRestoreAttacker::
|
BattleScript_PrimalReversionRestoreAttacker::
|
||||||
call BattleScript_PrimalReversionRet
|
call BattleScript_PrimalReversionRet
|
||||||
copybyte gBattlerAttacker, sSAVED_BATTLER
|
copybyte gBattlerAttacker, sSAVED_BATTLER
|
||||||
end2
|
end3
|
||||||
|
|
||||||
BattleScript_PrimalReversionRet::
|
BattleScript_PrimalReversionRet::
|
||||||
flushtextbox
|
flushtextbox
|
||||||
|
@ -7675,15 +7675,11 @@ BattleScript_EmergencyExitWildNoPopUp::
|
||||||
|
|
||||||
BattleScript_TraceActivates::
|
BattleScript_TraceActivates::
|
||||||
pause B_WAIT_TIME_SHORT
|
pause B_WAIT_TIME_SHORT
|
||||||
call BattleScript_AbilityPopUp
|
call BattleScript_AbilityPopUpScripting
|
||||||
printstring STRINGID_PKMNTRACED
|
printstring STRINGID_PKMNTRACED
|
||||||
waitmessage B_WAIT_TIME_LONG
|
waitmessage B_WAIT_TIME_LONG
|
||||||
settracedability BS_SCRIPTING
|
settracedability BS_SCRIPTING
|
||||||
switchinabilities BS_SCRIPTING
|
switchinabilities BS_SCRIPTING
|
||||||
return
|
|
||||||
|
|
||||||
BattleScript_TraceActivatesEnd3::
|
|
||||||
call BattleScript_TraceActivates
|
|
||||||
end3
|
end3
|
||||||
|
|
||||||
BattleScript_ReceiverActivates::
|
BattleScript_ReceiverActivates::
|
||||||
|
@ -10011,7 +10007,7 @@ BattleScript_BerserkGeneRet_End:
|
||||||
|
|
||||||
BattleScript_BoosterEnergyEnd2::
|
BattleScript_BoosterEnergyEnd2::
|
||||||
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1
|
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1
|
||||||
call BattleScript_AbilityPopUpTarget
|
call BattleScript_AbilityPopUpScripting
|
||||||
printstring STRINGID_BOOSTERENERGYACTIVATES
|
printstring STRINGID_BOOSTERENERGYACTIVATES
|
||||||
waitmessage B_WAIT_TIME_MED
|
waitmessage B_WAIT_TIME_MED
|
||||||
printstring STRINGID_STATWASHEIGHTENED
|
printstring STRINGID_STATWASHEIGHTENED
|
||||||
|
|
|
@ -93,7 +93,7 @@ struct ResourceFlags
|
||||||
#define RESOURCE_FLAG_ROOST 0x2
|
#define RESOURCE_FLAG_ROOST 0x2
|
||||||
#define RESOURCE_FLAG_UNBURDEN 0x4
|
#define RESOURCE_FLAG_UNBURDEN 0x4
|
||||||
#define RESOURCE_FLAG_UNUSED 0x8
|
#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_EMERGENCY_EXIT 0x20
|
||||||
#define RESOURCE_FLAG_NEUTRALIZING_GAS 0x40
|
#define RESOURCE_FLAG_NEUTRALIZING_GAS 0x40
|
||||||
#define RESOURCE_FLAG_ICE_FACE 0x80
|
#define RESOURCE_FLAG_ICE_FACE 0x80
|
||||||
|
@ -751,6 +751,7 @@ struct BattleStruct
|
||||||
u8 blunderPolicy:1; // should blunder policy activate
|
u8 blunderPolicy:1; // should blunder policy activate
|
||||||
u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
|
u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
|
||||||
u8 bouncedMoveIsUsed:1;
|
u8 bouncedMoveIsUsed:1;
|
||||||
|
u8 snatchedMoveIsUsed:1;
|
||||||
u8 descriptionSubmenu:1; // For Move Description window in move selection screen
|
u8 descriptionSubmenu:1; // For Move Description window in move selection screen
|
||||||
u8 ackBallUseBtn:1; // Used for the last used ball feature
|
u8 ackBallUseBtn:1; // Used for the last used ball feature
|
||||||
u8 ballSwapped: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_DrizzleActivates[];
|
||||||
extern const u8 BattleScript_SpeedBoostActivates[];
|
extern const u8 BattleScript_SpeedBoostActivates[];
|
||||||
extern const u8 BattleScript_TraceActivates[];
|
extern const u8 BattleScript_TraceActivates[];
|
||||||
extern const u8 BattleScript_TraceActivatesEnd3[];
|
|
||||||
extern const u8 BattleScript_RainDishActivates[];
|
extern const u8 BattleScript_RainDishActivates[];
|
||||||
extern const u8 BattleScript_SandstreamActivates[];
|
extern const u8 BattleScript_SandstreamActivates[];
|
||||||
extern const u8 BattleScript_ShedSkinActivates[];
|
extern const u8 BattleScript_ShedSkinActivates[];
|
||||||
|
|
|
@ -256,7 +256,7 @@ bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect);
|
||||||
bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument);
|
bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument);
|
||||||
bool32 MoveHasChargeTurnAdditionalEffect(u32 move);
|
bool32 MoveHasChargeTurnAdditionalEffect(u32 move);
|
||||||
bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef);
|
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 CanBeSlept(u32 battler, u32 ability);
|
||||||
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
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)
|
if ((gProtectStructs[gBattlerByTurnOrder[i]].stealMove) && gMovesInfo[gCurrentMove].snatchAffected)
|
||||||
{
|
{
|
||||||
gProtectStructs[gBattlerByTurnOrder[i]].stealMove = FALSE;
|
gProtectStructs[gBattlerByTurnOrder[i]].stealMove = FALSE;
|
||||||
|
gBattleStruct->snatchedMoveIsUsed = TRUE;
|
||||||
gBattleScripting.battler = gBattlerByTurnOrder[i];
|
gBattleScripting.battler = gBattlerByTurnOrder[i];
|
||||||
BattleScriptPushCursor();
|
BattleScriptPushCursor();
|
||||||
gBattlescriptCurrInstr = BattleScript_SnatchedMove;
|
gBattlescriptCurrInstr = BattleScript_SnatchedMove;
|
||||||
|
@ -6287,7 +6288,7 @@ static void Cmd_moveend(void)
|
||||||
gBattleScripting.moveendState++;
|
gBattleScripting.moveendState++;
|
||||||
break;
|
break;
|
||||||
case MOVEEND_DANCER: // Special case because it's so annoying
|
case MOVEEND_DANCER: // Special case because it's so annoying
|
||||||
if (gMovesInfo[gCurrentMove].danceMove)
|
if (gMovesInfo[gCurrentMove].danceMove && !gBattleStruct->snatchedMoveIsUsed)
|
||||||
{
|
{
|
||||||
u32 battler, nextDancer = 0;
|
u32 battler, nextDancer = 0;
|
||||||
bool32 hasDancerTriggered = FALSE;
|
bool32 hasDancerTriggered = FALSE;
|
||||||
|
@ -6431,6 +6432,7 @@ static void Cmd_moveend(void)
|
||||||
gBattleStruct->swapDamageCategory = FALSE;
|
gBattleStruct->swapDamageCategory = FALSE;
|
||||||
gBattleStruct->categoryOverride = FALSE;
|
gBattleStruct->categoryOverride = FALSE;
|
||||||
gBattleStruct->bouncedMoveIsUsed = FALSE;
|
gBattleStruct->bouncedMoveIsUsed = FALSE;
|
||||||
|
gBattleStruct->snatchedMoveIsUsed = FALSE;
|
||||||
gBattleStruct->enduredDamage = 0;
|
gBattleStruct->enduredDamage = 0;
|
||||||
gBattleStruct->additionalEffectsCounter = 0;
|
gBattleStruct->additionalEffectsCounter = 0;
|
||||||
gBattleStruct->poisonPuppeteerConfusion = FALSE;
|
gBattleStruct->poisonPuppeteerConfusion = FALSE;
|
||||||
|
@ -11537,7 +11539,7 @@ static void Cmd_stockpiletohpheal(void)
|
||||||
|
|
||||||
const u8 *failInstr = cmd->failInstr;
|
const u8 *failInstr = cmd->failInstr;
|
||||||
|
|
||||||
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0)
|
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0 && !gBattleStruct->snatchedMoveIsUsed)
|
||||||
{
|
{
|
||||||
gBattlescriptCurrInstr = failInstr;
|
gBattlescriptCurrInstr = failInstr;
|
||||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FAILED;
|
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FAILED;
|
||||||
|
@ -11553,14 +11555,22 @@ static void Cmd_stockpiletohpheal(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter));
|
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)
|
if (gBattleMoveDamage == 0)
|
||||||
gBattleMoveDamage = 1;
|
gBattleMoveDamage = 1;
|
||||||
gBattleMoveDamage *= -1;
|
gBattleMoveDamage *= -1;
|
||||||
|
|
||||||
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
|
||||||
gBattleStruct->moveEffect2 = MOVE_EFFECT_STOCKPILE_WORE_OFF;
|
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
gBattlerTarget = gBattlerAttacker;
|
gBattlerTarget = gBattlerAttacker;
|
||||||
}
|
}
|
||||||
|
@ -17122,30 +17132,18 @@ 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
|
// 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;
|
gProtectStructs[gBattlerTarget].quash = TRUE;
|
||||||
|
|
||||||
if (B_QUASH_TURN_ORDER < GEN_8)
|
// this implementation assumes turn order is correct when using Quash
|
||||||
|
i = GetBattlerTurnOrderNum(gBattlerTarget);
|
||||||
|
for (j = i + 1; j < gBattlersCount; j++)
|
||||||
{
|
{
|
||||||
// Gen 7- config makes target go last so that the order of quash targets is kept for the correct turn order
|
// Gen 7- config makes target go last so that the order of quash targets is kept for the correct turn order
|
||||||
j = GetBattlerTurnOrderNum(gBattlerTarget);
|
// Gen 8+ config alters Turn Order of the target according to speed, dynamic speed should handle the rest
|
||||||
for (i = j + 1; i < gBattlersCount; i++)
|
if (B_QUASH_TURN_ORDER < GEN_8 || GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1)
|
||||||
{
|
|
||||||
SwapTurnOrder(i, j);
|
SwapTurnOrder(i, j);
|
||||||
j++;
|
else
|
||||||
}
|
break;
|
||||||
}
|
i++;
|
||||||
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++)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
SwapTurnOrder(i, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4368,13 +4368,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||||
|
|
||||||
if (gSpecialStatuses[battler].switchInAbilityDone)
|
if (gSpecialStatuses[battler].switchInAbilityDone)
|
||||||
break;
|
break;
|
||||||
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_TRACED)
|
|
||||||
break;
|
|
||||||
|
|
||||||
side = (BATTLE_OPPOSITE(GetBattlerPosition(battler))) & BIT_SIDE;
|
side = (BATTLE_OPPOSITE(GetBattlerPosition(battler))) & BIT_SIDE;
|
||||||
target1 = GetBattlerAtPosition(side);
|
target1 = GetBattlerAtPosition(side);
|
||||||
target2 = GetBattlerAtPosition(side + BIT_FLANK);
|
target2 = GetBattlerAtPosition(side + BIT_FLANK);
|
||||||
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
|
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||||
{
|
{
|
||||||
if (!gAbilitiesInfo[gBattleMons[target1].ability].cantBeTraced && gBattleMons[target1].hp != 0
|
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)
|
if (effect != 0)
|
||||||
{
|
{
|
||||||
BattleScriptPushCursorAndCallback(BattleScript_TraceActivatesEnd3);
|
BattleScriptPushCursorAndCallback(BattleScript_TraceActivates);
|
||||||
gBattleResources->flags->flags[battler] &= ~RESOURCE_FLAG_TRACED;
|
|
||||||
gBattleStruct->tracedAbility[battler] = gLastUsedAbility = gBattleMons[chosenTarget].ability;
|
gBattleStruct->tracedAbility[battler] = gLastUsedAbility = gBattleMons[chosenTarget].ability;
|
||||||
RecordAbilityBattle(chosenTarget, gLastUsedAbility); // Record the opposing battler has this 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_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, chosenTarget, gBattlerPartyIndexes[chosenTarget])
|
||||||
PREPARE_ABILITY_BUFFER(gBattleTextBuff2, gLastUsedAbility)
|
PREPARE_ABILITY_BUFFER(gBattleTextBuff2, gLastUsedAbility)
|
||||||
|
@ -5214,7 +5210,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||||
break;
|
break;
|
||||||
case ABILITY_GOOD_AS_GOLD:
|
case ABILITY_GOOD_AS_GOLD:
|
||||||
if (IS_MOVE_STATUS(gCurrentMove)
|
if (IS_MOVE_STATUS(gCurrentMove)
|
||||||
&& !(moveTarget & MOVE_TARGET_USER)
|
|
||||||
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
|
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
|
||||||
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
|
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
|
||||||
effect = 3;
|
effect = 3;
|
||||||
|
@ -6388,14 +6383,14 @@ bool32 TryPrimalReversion(u32 battler)
|
||||||
{
|
{
|
||||||
if (gBattlerAttacker == battler)
|
if (gBattlerAttacker == battler)
|
||||||
{
|
{
|
||||||
BattleScriptExecute(BattleScript_PrimalReversion);
|
BattleScriptPushCursorAndCallback(BattleScript_PrimalReversion);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// edge case for scenarios like a switch-in after activated eject button
|
// edge case for scenarios like a switch-in after activated eject button
|
||||||
gBattleScripting.savedBattler = gBattlerAttacker;
|
gBattleScripting.savedBattler = gBattlerAttacker;
|
||||||
gBattlerAttacker = battler;
|
gBattlerAttacker = battler;
|
||||||
BattleScriptExecute(BattleScript_PrimalReversionRestoreAttacker);
|
BattleScriptPushCursorAndCallback(BattleScript_PrimalReversionRestoreAttacker);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -8706,7 +8701,7 @@ u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc)
|
||||||
|
|
||||||
u32 GetMoveTargetCount(u32 move, u32 battlerAtk, u32 battlerDef)
|
u32 GetMoveTargetCount(u32 move, u32 battlerAtk, u32 battlerDef)
|
||||||
{
|
{
|
||||||
switch (GetBattlerMoveTargetType(gBattlerAttacker, move))
|
switch (GetBattlerMoveTargetType(battlerAtk, move))
|
||||||
{
|
{
|
||||||
case MOVE_TARGET_BOTH:
|
case MOVE_TARGET_BOTH:
|
||||||
return !(gAbsentBattlerFlags & gBitTable[battlerDef])
|
return !(gAbsentBattlerFlags & gBitTable[battlerDef])
|
||||||
|
@ -11816,19 +11811,19 @@ bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef)
|
||||||
&& battlerDef != BATTLE_PARTNER(battlerAtk));
|
&& battlerDef != BATTLE_PARTNER(battlerAtk));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool32 DoesCurrentTargetHaveAbilityImmunity(void)
|
static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerDef)
|
||||||
{
|
{
|
||||||
return (AbilityBattleEffects(ABILITYEFFECT_WOULD_BLOCK, gBattlerTarget, 0, 0, 0)
|
return (AbilityBattleEffects(ABILITYEFFECT_WOULD_BLOCK, battlerDef, 0, 0, 0)
|
||||||
|| AbilityBattleEffects(ABILITYEFFECT_WOULD_ABSORB, gBattlerTarget, 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;
|
u32 moveType = 0;
|
||||||
GET_MOVE_TYPE(gCurrentMove, moveType);
|
GET_MOVE_TYPE(gCurrentMove, moveType);
|
||||||
|
|
||||||
return ((CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, BattlerAtk, battlerDef, GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0))
|
return ((CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0))
|
||||||
|| IsBattlerProtected(BattlerAtk, battlerDef, gCurrentMove)
|
|| IsBattlerProtected(battlerAtk, battlerDef, gCurrentMove)
|
||||||
|| IsSemiInvulnerable(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")
|
DOUBLE_BATTLE_TEST("Dancer doesn't call a move that didn't execute due to Powder")
|
||||||
{
|
{
|
||||||
GIVEN {
|
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")
|
DOUBLE_BATTLE_TEST("Trace respects the turn order")
|
||||||
{
|
{
|
||||||
GIVEN {
|
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);
|
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")
|
DOUBLE_BATTLE_TEST("Dragon Darts strikes the ally twice if the target is in a semi-invulnerable turn")
|
||||||
{
|
{
|
||||||
GIVEN {
|
GIVEN {
|
||||||
|
|
Loading…
Reference in a new issue