Merge branch '_RHH/upcoming' into _RHH/pr/upcoming/lighting-expansion-v2
This commit is contained in:
commit
8c57172f2a
@ -640,7 +640,7 @@ BattleScript_AffectionBasedStatus_HealFreezeString:
|
||||
printstring STRINGID_ATTACKERMELTEDTHEICE
|
||||
goto BattleScript_AffectionBasedStatusHeal_Continue
|
||||
BattleScript_AffectionBasedStatus_HealFrostbiteString:
|
||||
printstring STRINGID_ATTACKERMELTEDTHEICE
|
||||
printstring STRINGID_ATTACKERHEALEDITSFROSTBITE
|
||||
BattleScript_AffectionBasedStatusHeal_Continue:
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
clearstatus BS_ATTACKER
|
||||
@ -1563,6 +1563,7 @@ BattleScript_RototillerMoveTargetEnd:
|
||||
moveendto MOVEEND_NEXT_TARGET
|
||||
addbyte gBattlerTarget, 1
|
||||
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_RototillerLoop
|
||||
restoretarget
|
||||
end
|
||||
|
||||
BattleScript_RototillerCantRaiseMultipleStats:
|
||||
@ -1743,8 +1744,6 @@ BattleScript_EffectCopycat::
|
||||
trycopycat BattleScript_CopycatFail
|
||||
attackanimation
|
||||
waitanimation
|
||||
setbyte sB_ANIM_TURN, 0
|
||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
||||
jumptocalledmove TRUE
|
||||
BattleScript_CopycatFail:
|
||||
ppreduce
|
||||
@ -1762,8 +1761,6 @@ BattleScript_EffectInstruct::
|
||||
copybyte gBattlerTarget, gEffectBattler
|
||||
printstring STRINGID_USEDINSTRUCTEDMOVE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
setbyte sB_ANIM_TURN, 0
|
||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
||||
jumptocalledmove TRUE
|
||||
|
||||
BattleScript_EffectAutotomize::
|
||||
@ -2187,8 +2184,6 @@ BattleScript_EffectMeFirst::
|
||||
trymefirst BattleScript_FailedFromPpReduce
|
||||
attackanimation
|
||||
waitanimation
|
||||
setbyte sB_ANIM_TURN, 0
|
||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
||||
jumptocalledmove TRUE
|
||||
|
||||
BattleScript_EffectAttackSpAttackUp::
|
||||
@ -3657,12 +3652,12 @@ BattleScript_EffectParalyze::
|
||||
jumpifmovehadnoeffect BattleScript_ButItFailed
|
||||
jumpifstatus BS_TARGET, STATUS1_PARALYSIS, BattleScript_AlreadyParalyzed
|
||||
jumpifelectricabilityaffected BS_TARGET, ABILITY_VOLT_ABSORB, BattleScript_VoltAbsorbHeal
|
||||
clearmoveresultflags MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE
|
||||
tryparalyzetype BS_ATTACKER, BS_TARGET, BattleScript_NotAffected
|
||||
jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed
|
||||
jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents
|
||||
accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE
|
||||
jumpifsafeguard BattleScript_SafeguardProtected
|
||||
clearmoveresultflags MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE
|
||||
attackanimation
|
||||
waitanimation
|
||||
seteffectprimary MOVE_EFFECT_PARALYSIS
|
||||
@ -3843,8 +3838,6 @@ BattleScript_EffectMetronome::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
attackanimation
|
||||
waitanimation
|
||||
setbyte sB_ANIM_TURN, 0
|
||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
||||
metronome
|
||||
|
||||
BattleScript_EffectLeechSeed::
|
||||
@ -4051,8 +4044,6 @@ BattleScript_SleepTalkIsAsleep::
|
||||
BattleScript_SleepTalkUsingMove::
|
||||
attackanimation
|
||||
waitanimation
|
||||
setbyte sB_ANIM_TURN, 0
|
||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
||||
jumptocalledmove TRUE
|
||||
|
||||
BattleScript_EffectDestinyBond::
|
||||
@ -4167,11 +4158,15 @@ BattleScript_CurseTrySpeed::
|
||||
setbyte sB_ANIM_TURN, 1
|
||||
attackanimation
|
||||
waitanimation
|
||||
setbyte sSTAT_ANIM_PLAYED, FALSE
|
||||
playstatchangeanimation BS_ATTACKER, BIT_SPEED, STAT_CHANGE_NEGATIVE
|
||||
setstatchanger STAT_SPEED, 1, TRUE
|
||||
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CurseTryAttack
|
||||
printfromtable gStatDownStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_CurseTryAttack::
|
||||
setbyte sSTAT_ANIM_PLAYED, FALSE
|
||||
playstatchangeanimation BS_ATTACKER, BIT_ATK | BIT_DEF, 0
|
||||
setstatchanger STAT_ATK, 1, FALSE
|
||||
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CurseTryDefense
|
||||
printfromtable gStatUpStringIds
|
||||
@ -5070,8 +5065,6 @@ BattleScript_EffectAssist::
|
||||
assistattackselect BattleScript_FailedFromPpReduce
|
||||
attackanimation
|
||||
waitanimation
|
||||
setbyte sB_ANIM_TURN, 0
|
||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
||||
jumptocalledmove TRUE
|
||||
|
||||
BattleScript_EffectIngrain::
|
||||
@ -5112,6 +5105,7 @@ BattleScript_EffectBrickBreak::
|
||||
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
||||
attackstring
|
||||
ppreduce
|
||||
typecalc
|
||||
removelightscreenreflect
|
||||
critcalc
|
||||
damagecalc
|
||||
@ -8651,8 +8645,6 @@ BattleScript_BattleBondActivatesOnMoveEndAttacker::
|
||||
BattleScript_DancerActivates::
|
||||
call BattleScript_AbilityPopUp
|
||||
waitmessage B_WAIT_TIME_SHORT
|
||||
setbyte sB_ANIM_TURN, 0
|
||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
||||
orword gHitMarker, HITMARKER_ALLOW_NO_PP
|
||||
jumptocalledmove TRUE
|
||||
|
||||
|
||||
@ -554,6 +554,10 @@ Causes the test to fail if a and b compare incorrectly, e.g.
|
||||
EXPECT_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
||||
```
|
||||
|
||||
### `FORCE_MOVE_ANIM`
|
||||
`FORCE_MOVE_ANIM(TRUE)`
|
||||
Forces the moves in the current test to do their animations in headless mode. Useful for debugging animations.
|
||||
|
||||
## Overworld Command Reference
|
||||
|
||||
### `OVERWORLD_SCRIPT`
|
||||
|
||||
@ -14,6 +14,6 @@ JASC-PAL
|
||||
96 168 120
|
||||
64 136 96
|
||||
232 232 248
|
||||
152 40 64
|
||||
39 44 149
|
||||
0 0 0
|
||||
0 0 0
|
||||
|
||||
@ -835,6 +835,7 @@ struct BattleStruct
|
||||
u8 padding3:2;
|
||||
struct MessageStatus slideMessageStatus;
|
||||
u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT];
|
||||
u8 embodyAspectBoost[NUM_BATTLE_SIDES];
|
||||
};
|
||||
|
||||
// The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider,
|
||||
|
||||
@ -172,6 +172,7 @@ enum SleepClauseBlock
|
||||
|
||||
void HandleAction_ThrowBall(void);
|
||||
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move);
|
||||
bool32 HandleMoveTargetRedirection(void);
|
||||
void HandleAction_UseMove(void);
|
||||
void HandleAction_Switch(void);
|
||||
void HandleAction_UseItem(void);
|
||||
|
||||
@ -533,6 +533,20 @@ static inline s32 SetFixedMoveBasePower(u32 battlerAtk, u32 move)
|
||||
return fixedBasePower;
|
||||
}
|
||||
|
||||
static inline void AI_StoreBattlerTypes(u32 battlerAtk, u32 *types)
|
||||
{
|
||||
types[0] = gBattleMons[battlerAtk].types[0];
|
||||
types[1] = gBattleMons[battlerAtk].types[1];
|
||||
types[2] = gBattleMons[battlerAtk].types[2];
|
||||
}
|
||||
|
||||
static inline void AI_RestoreBattlerTypes(u32 battlerAtk, u32 *types)
|
||||
{
|
||||
gBattleMons[battlerAtk].types[0] = types[0];
|
||||
gBattleMons[battlerAtk].types[1] = types[1];
|
||||
gBattleMons[battlerAtk].types[2] = types[2];
|
||||
}
|
||||
|
||||
static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCalcData, s32 *expectedDamage, s32 *minimumDamage, u32 holdEffectAtk, u32 abilityAtk)
|
||||
{
|
||||
u32 move = damageCalcData->move;
|
||||
@ -658,6 +672,9 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
{
|
||||
s32 critChanceIndex, fixedBasePower;
|
||||
|
||||
u32 types[3];
|
||||
AI_StoreBattlerTypes(battlerAtk, types);
|
||||
|
||||
ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, moveType);
|
||||
fixedBasePower = SetFixedMoveBasePower(battlerAtk, move);
|
||||
|
||||
@ -735,6 +752,8 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
aiData->holdEffects[battlerAtk],
|
||||
aiData->abilities[battlerAtk]);
|
||||
}
|
||||
|
||||
AI_RestoreBattlerTypes(battlerAtk, types);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1068,8 +1087,15 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 moveConsidered)
|
||||
u32 abilityAI = AI_DATA->abilities[battlerAI];
|
||||
u32 abilityPlayer = AI_DATA->abilities[battler];
|
||||
|
||||
if (GetBattleMovePriority(battlerAI, moveConsidered) > 0)
|
||||
u32 predictedMove = AI_DATA->lastUsedMove[battler]; // TODO update for move prediction
|
||||
|
||||
s8 aiPriority = GetBattleMovePriority(battlerAI, moveConsidered);
|
||||
s8 playerPriority = GetBattleMovePriority(battler, predictedMove);
|
||||
|
||||
if (aiPriority > playerPriority)
|
||||
return AI_IS_FASTER;
|
||||
else if (aiPriority < playerPriority)
|
||||
return AI_IS_SLOWER;
|
||||
|
||||
speedBattlerAI = GetBattlerTotalSpeedStatArgs(battlerAI, abilityAI, holdEffectAI);
|
||||
speedBattler = GetBattlerTotalSpeedStatArgs(battler, abilityPlayer, holdEffectPlayer);
|
||||
|
||||
@ -344,6 +344,7 @@ static bool8 CanBurnHitThaw(u16 move);
|
||||
static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent);
|
||||
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove);
|
||||
static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move);
|
||||
static void ResetValuesForCalledMove(void);
|
||||
|
||||
static void Cmd_attackcanceler(void);
|
||||
static void Cmd_accuracycheck(void);
|
||||
@ -8746,6 +8747,18 @@ static void Cmd_hidepartystatussummary(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void ResetValuesForCalledMove(void)
|
||||
{
|
||||
if (gBattlerByTurnOrder[gCurrentTurnActionNumber] != gBattlerAttacker)
|
||||
gBattleStruct->atkCancellerTracker = 0;
|
||||
else
|
||||
SetAtkCancellerForCalledMove();
|
||||
gBattleScripting.animTurn = 0;
|
||||
gBattleScripting.animTargetsHit = 0;
|
||||
SetTypeBeforeUsingMove(gCurrentMove, gBattlerAttacker);
|
||||
HandleMoveTargetRedirection();
|
||||
}
|
||||
|
||||
static void Cmd_jumptocalledmove(void)
|
||||
{
|
||||
CMD_ARGS(bool8 notChosenMove);
|
||||
@ -8755,6 +8768,8 @@ static void Cmd_jumptocalledmove(void)
|
||||
else
|
||||
gChosenMove = gCurrentMove = gCalledMove;
|
||||
|
||||
ResetValuesForCalledMove();
|
||||
|
||||
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
||||
}
|
||||
|
||||
@ -10811,10 +10826,8 @@ static void Cmd_various(void)
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else
|
||||
{
|
||||
SetTypeBeforeUsingMove(gCalledMove, gBattlerTarget);
|
||||
gEffectBattler = gBattleStruct->lastMoveTarget[gBattlerTarget];
|
||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||
gBattleStruct->atkCancellerTracker = 0;
|
||||
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, battler, gBattlerPartyIndexes[battler]);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
@ -11804,8 +11817,8 @@ static void SetMoveForMirrorMove(u32 move)
|
||||
gCurrentMove = move;
|
||||
}
|
||||
|
||||
SetAtkCancellerForCalledMove();
|
||||
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||
ResetValuesForCalledMove();
|
||||
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
||||
}
|
||||
|
||||
@ -13333,10 +13346,10 @@ static void Cmd_metronome(void)
|
||||
#endif
|
||||
|
||||
gCurrentMove = RandomUniformExcept(RNG_METRONOME, 1, moveCount - 1, InvalidMetronomeMove);
|
||||
SetAtkCancellerForCalledMove();
|
||||
PrepareStringBattle(STRINGID_WAGGLINGAFINGER, gBattlerAttacker);
|
||||
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
||||
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||
ResetValuesForCalledMove();
|
||||
}
|
||||
|
||||
static void Cmd_dmgtolevel(void)
|
||||
@ -18046,14 +18059,10 @@ void BS_JumpIfBlockedBySoundproof(void)
|
||||
void BS_SetMagicCoatTarget(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
u32 side;
|
||||
gBattleStruct->attackerBeforeBounce = gBattleScripting.battler = gBattlerAttacker;
|
||||
gBattlerAttacker = gBattlerTarget;
|
||||
side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker));
|
||||
if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove))
|
||||
gBattlerTarget = gSideTimers[side].followmeTarget;
|
||||
else
|
||||
gBattlerTarget = gBattleStruct->attackerBeforeBounce;
|
||||
gBattlerTarget = gBattleStruct->attackerBeforeBounce;
|
||||
HandleMoveTargetRedirection();
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
@ -234,11 +234,69 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 HandleMoveTargetRedirection(void)
|
||||
{
|
||||
u32 redirectorOrderNum = MAX_BATTLERS_COUNT;
|
||||
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
|
||||
u32 moveType = GetBattleMoveType(gCurrentMove);
|
||||
u32 moveEffect = GetMoveEffect(gCurrentMove);
|
||||
u32 side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker));
|
||||
u32 ability = GetBattlerAbility(gBattleStruct->moveTarget[gBattlerAttacker]);
|
||||
|
||||
if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove)
|
||||
&& moveTarget == MOVE_TARGET_SELECTED
|
||||
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget))
|
||||
{
|
||||
gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = gSideTimers[side].followmeTarget; // follow me moxie fix
|
||||
return TRUE;
|
||||
}
|
||||
else if (IsDoubleBattle()
|
||||
&& gSideTimers[side].followmeTimer == 0
|
||||
&& (!IsBattleMoveStatus(gCurrentMove) || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS))
|
||||
&& ((ability != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC)
|
||||
|| (ability != ABILITY_STORM_DRAIN && moveType == TYPE_WATER)))
|
||||
{
|
||||
// Find first battler that redirects the move (in turn order)
|
||||
u32 battler;
|
||||
for (battler = 0; battler < gBattlersCount; battler++)
|
||||
{
|
||||
ability = GetBattlerAbility(battler);
|
||||
if ((B_REDIRECT_ABILITY_ALLIES >= GEN_4 || !IsAlly(gBattlerAttacker, battler))
|
||||
&& battler != gBattlerAttacker
|
||||
&& gBattleStruct->moveTarget[gBattlerAttacker] != battler
|
||||
&& ((ability == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC)
|
||||
|| (ability == ABILITY_STORM_DRAIN && moveType == TYPE_WATER))
|
||||
&& GetBattlerTurnOrderNum(battler) < redirectorOrderNum
|
||||
&& moveEffect != EFFECT_SNIPE_SHOT
|
||||
&& moveEffect != EFFECT_PLEDGE
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_PROPELLER_TAIL
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_STALWART)
|
||||
{
|
||||
redirectorOrderNum = GetBattlerTurnOrderNum(battler);
|
||||
}
|
||||
}
|
||||
if (redirectorOrderNum != MAX_BATTLERS_COUNT)
|
||||
{
|
||||
u16 battlerAbility;
|
||||
battler = gBattlerByTurnOrder[redirectorOrderNum];
|
||||
battlerAbility = GetBattlerAbility(battler);
|
||||
|
||||
RecordAbilityBattle(battler, gBattleMons[battler].ability);
|
||||
if (battlerAbility == ABILITY_LIGHTNING_ROD && gCurrentMove != MOVE_TEATIME)
|
||||
gSpecialStatuses[battler].lightningRodRedirected = TRUE;
|
||||
else if (battlerAbility == ABILITY_STORM_DRAIN)
|
||||
gSpecialStatuses[battler].stormDrainRedirected = TRUE;
|
||||
gBattlerTarget = battler;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Functions
|
||||
void HandleAction_UseMove(void)
|
||||
{
|
||||
u32 battler, i, side, moveType, ability, var = MAX_BATTLERS_COUNT;
|
||||
u16 moveTarget;
|
||||
u32 i;
|
||||
|
||||
gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber];
|
||||
if (gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags
|
||||
@ -308,7 +366,6 @@ void HandleAction_UseMove(void)
|
||||
|
||||
// Set dynamic move type.
|
||||
SetTypeBeforeUsingMove(gChosenMove, gBattlerAttacker);
|
||||
moveType = GetBattleMoveType(gCurrentMove);
|
||||
|
||||
// check Z-Move used
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gCurrentMove) && !IsZMove(gCurrentMove))
|
||||
@ -323,117 +380,44 @@ void HandleAction_UseMove(void)
|
||||
gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove);
|
||||
}
|
||||
|
||||
moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
|
||||
u32 moveEffect = GetMoveEffect(gCurrentMove);
|
||||
|
||||
// choose target
|
||||
side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker));
|
||||
ability = GetBattlerAbility(gBattleStruct->moveTarget[gBattlerAttacker]);
|
||||
if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove)
|
||||
&& moveTarget == MOVE_TARGET_SELECTED
|
||||
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget))
|
||||
if (!HandleMoveTargetRedirection())
|
||||
{
|
||||
gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = gSideTimers[side].followmeTarget; // follow me moxie fix
|
||||
}
|
||||
else if (IsDoubleBattle()
|
||||
&& gSideTimers[side].followmeTimer == 0
|
||||
&& !gBattleStruct->battlerState[gBattleStruct->moveTarget[gBattlerAttacker]].pursuitTarget
|
||||
&& (!IsBattleMoveStatus(gCurrentMove) || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS))
|
||||
&& ((ability != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC)
|
||||
|| (ability != ABILITY_STORM_DRAIN && moveType == TYPE_WATER)))
|
||||
{
|
||||
// Find first battler that redirects the move (in turn order)
|
||||
for (battler = 0; battler < gBattlersCount; battler++)
|
||||
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
|
||||
if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM)
|
||||
{
|
||||
ability = GetBattlerAbility(battler);
|
||||
if ((B_REDIRECT_ABILITY_ALLIES >= GEN_4 || !IsBattlerAlly(gBattlerAttacker, battler))
|
||||
&& battler != gBattlerAttacker
|
||||
&& gBattleStruct->moveTarget[gBattlerAttacker] != battler
|
||||
&& ((ability == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC)
|
||||
|| (ability == ABILITY_STORM_DRAIN && moveType == TYPE_WATER))
|
||||
&& GetBattlerTurnOrderNum(battler) < var
|
||||
&& moveEffect != EFFECT_SNIPE_SHOT
|
||||
&& moveEffect != EFFECT_PLEDGE
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_PROPELLER_TAIL
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_STALWART)
|
||||
{
|
||||
var = GetBattlerTurnOrderNum(battler);
|
||||
}
|
||||
}
|
||||
if (var == MAX_BATTLERS_COUNT)
|
||||
{
|
||||
if (moveTarget & MOVE_TARGET_RANDOM)
|
||||
{
|
||||
gBattlerTarget = SetRandomTarget(gBattlerAttacker);
|
||||
}
|
||||
else if (moveTarget & MOVE_TARGET_FOES_AND_ALLY)
|
||||
{
|
||||
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
|
||||
{
|
||||
if (gBattlerTarget == gBattlerAttacker)
|
||||
continue;
|
||||
if (IsBattlerAlive(gBattlerTarget))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlerTarget = gBattleStruct->moveTarget[gBattlerAttacker];
|
||||
}
|
||||
|
||||
if (!IsBattlerAlive(gBattlerTarget) && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget))
|
||||
gBattlerTarget = SetRandomTarget(gBattlerAttacker);
|
||||
if (gAbsentBattlerFlags & (1u << gBattlerTarget)
|
||||
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget))
|
||||
{
|
||||
gBattlerTarget = GetPartnerBattler(gBattlerTarget);
|
||||
}
|
||||
}
|
||||
else if (moveTarget == MOVE_TARGET_ALLY)
|
||||
{
|
||||
if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)))
|
||||
gBattlerTarget = BATTLE_PARTNER(gBattlerAttacker);
|
||||
else
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
}
|
||||
else if (IsDoubleBattle() && moveTarget == MOVE_TARGET_FOES_AND_ALLY)
|
||||
{
|
||||
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
|
||||
{
|
||||
if (gBattlerTarget == gBattlerAttacker)
|
||||
continue;
|
||||
if (IsBattlerAlive(gBattlerTarget))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 battlerAbility;
|
||||
battler = gBattlerByTurnOrder[var];
|
||||
battlerAbility = GetBattlerAbility(battler);
|
||||
|
||||
RecordAbilityBattle(battler, gBattleMons[battler].ability);
|
||||
if (battlerAbility == ABILITY_LIGHTNING_ROD && gCurrentMove != MOVE_TEATIME)
|
||||
gSpecialStatuses[battler].lightningRodRedirected = TRUE;
|
||||
else if (battlerAbility == ABILITY_STORM_DRAIN)
|
||||
gSpecialStatuses[battler].stormDrainRedirected = TRUE;
|
||||
gBattlerTarget = battler;
|
||||
}
|
||||
}
|
||||
else if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM)
|
||||
{
|
||||
gBattlerTarget = SetRandomTarget(gBattlerAttacker);
|
||||
if (gAbsentBattlerFlags & (1u << gBattlerTarget)
|
||||
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget))
|
||||
{
|
||||
gBattlerTarget = GetPartnerBattler(gBattlerTarget);
|
||||
}
|
||||
}
|
||||
else if (moveTarget == MOVE_TARGET_ALLY)
|
||||
{
|
||||
if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)))
|
||||
gBattlerTarget = BATTLE_PARTNER(gBattlerAttacker);
|
||||
else
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
}
|
||||
else if (IsDoubleBattle() && moveTarget == MOVE_TARGET_FOES_AND_ALLY)
|
||||
{
|
||||
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
|
||||
{
|
||||
if (gBattlerTarget == gBattlerAttacker)
|
||||
continue;
|
||||
if (IsBattlerAlive(gBattlerTarget))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlerTarget = gBattleStruct->moveTarget[gBattlerAttacker];
|
||||
if (!IsBattlerAlive(gBattlerTarget)
|
||||
&& moveTarget != MOVE_TARGET_OPPONENTS_FIELD
|
||||
&& (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)))
|
||||
{
|
||||
gBattlerTarget = GetPartnerBattler(gBattlerTarget);
|
||||
gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker);
|
||||
if (!IsBattlerAlive(gBattlerTarget)
|
||||
&& moveTarget != MOVE_TARGET_OPPONENTS_FIELD
|
||||
&& (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)))
|
||||
{
|
||||
gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3215,6 +3199,8 @@ static void CancellerAsleep(u32 *effect)
|
||||
gBattleMons[gBattlerAttacker].status1 -= toSub;
|
||||
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
|
||||
{
|
||||
u32 moveEffect = GetMoveEffect(gChosenMove);
|
||||
if (moveEffect != EFFECT_SNORE && moveEffect != EFFECT_SLEEP_TALK)
|
||||
if (gChosenMove != MOVE_SNORE && gChosenMove != MOVE_SLEEP_TALK)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep;
|
||||
@ -3551,7 +3537,7 @@ static void CancellerThaw(u32 *effect)
|
||||
|
||||
static void CancellerStanceChangeTwo(u32 *effect)
|
||||
{
|
||||
if (B_STANCE_CHANGE_FAIL >= GEN_7 && TryFormChangeBeforeMove())
|
||||
if (B_STANCE_CHANGE_FAIL >= GEN_7 && !gBattleStruct->isAtkCancelerForCalledMove && TryFormChangeBeforeMove())
|
||||
*effect = 1;
|
||||
}
|
||||
|
||||
@ -5306,7 +5292,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
case ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK:
|
||||
case ABILITY_EMBODY_ASPECT_WELLSPRING_MASK:
|
||||
case ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK:
|
||||
if (!gSpecialStatuses[battler].switchInAbilityDone)
|
||||
if (!gSpecialStatuses[battler].switchInAbilityDone
|
||||
&& !(gBattleStruct->embodyAspectBoost[GetBattlerSide(battler)] & (1u << gBattlerPartyIndexes[battler])))
|
||||
{
|
||||
u32 stat;
|
||||
|
||||
@ -5325,6 +5312,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
gBattleScripting.savedBattler = gBattlerAttacker;
|
||||
gBattlerAttacker = battler;
|
||||
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
|
||||
gBattleStruct->embodyAspectBoost[GetBattlerSide(battler)] |= 1u << gBattlerPartyIndexes[battler];
|
||||
SET_STATCHANGER(stat, 1, FALSE);
|
||||
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
|
||||
effect++;
|
||||
@ -6297,7 +6285,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
// Set bit and save Dancer mon's original target
|
||||
gSpecialStatuses[battler].dancerUsedMove = TRUE;
|
||||
gSpecialStatuses[battler].dancerOriginalTarget = gBattleStruct->moveTarget[battler] | 0x4;
|
||||
gBattleStruct->atkCancellerTracker = 0;
|
||||
gBattlerAttacker = gBattlerAbility = battler;
|
||||
gCalledMove = gCurrentMove;
|
||||
|
||||
@ -6306,7 +6293,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
|
||||
// Edge case for dance moves that hit multiply targets
|
||||
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
|
||||
SetTypeBeforeUsingMove(gCalledMove, battler);
|
||||
|
||||
// Make sure that the target isn't an ally - if it is, target the original user
|
||||
if (IsBattlerAlly(gBattlerTarget, gBattlerAttacker))
|
||||
|
||||
@ -105,7 +105,7 @@ static const u8 sFeintDescription[] = _(
|
||||
"An attack that hits foes\n"
|
||||
"using moves like Protect.");
|
||||
|
||||
const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
||||
const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
{
|
||||
[MOVE_NONE] =
|
||||
{
|
||||
|
||||
@ -3439,7 +3439,7 @@ static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId) //https://githu
|
||||
//Moves
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] == MOVE_NONE || moves[i] == 0xFF || moves[i] >= MOVES_COUNT)
|
||||
if (moves[i] == MOVE_NONE || moves[i] >= MOVES_COUNT)
|
||||
continue;
|
||||
|
||||
SetMonMoveSlot(&mon, moves[i], i);
|
||||
|
||||
@ -38,8 +38,6 @@ static void Task_DrawFieldMessage(u8 taskId)
|
||||
LoadMessageBoxAndBorderGfx();
|
||||
task->tState++;
|
||||
break;
|
||||
task->tState++;
|
||||
break;
|
||||
case 1:
|
||||
DrawDialogueFrame(0, TRUE);
|
||||
task->tState++;
|
||||
|
||||
@ -6074,15 +6074,8 @@ const u8 *GetTrainerPartnerName(void)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||
{
|
||||
if (gPartnerTrainerId == TRAINER_PARTNER(PARTNER_STEVEN))
|
||||
{
|
||||
return GetTrainerNameFromId(PARTNER_STEVEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetFrontierTrainerName(gStringVar1, gPartnerTrainerId);
|
||||
return gStringVar1;
|
||||
}
|
||||
GetFrontierTrainerName(gStringVar1, gPartnerTrainerId);
|
||||
return gStringVar1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -57,3 +57,26 @@ SINGLE_BATTLE_TEST("Embody Aspect activates when it's no longer effected by Neut
|
||||
MESSAGE("The opposing Ogerpon's Embody Aspect raised its Speed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Embody Aspect raises Speed only once per battle")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_OGERPON_TEAL_TERA) { Ability(ABILITY_EMBODY_ASPECT_TEAL_MASK); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { SWITCH(opponent, 1); }
|
||||
TURN { SWITCH(opponent, 0); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_EMBODY_ASPECT_TEAL_MASK);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("The opposing Ogerpon's Embody Aspect raised its Speed!");
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_EMBODY_ASPECT_TEAL_MASK);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("The opposing Ogerpon's Embody Aspect raised its Speed!");
|
||||
}
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -831,3 +831,17 @@ AI_SINGLE_BATTLE_TEST("AI stays choice locked into moves in spite of the player'
|
||||
TURN { EXPECT_MOVE(opponent, aiMove); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI won't use Sucker Punch if it expects a move of the same priority bracket and the opponent is faster")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1);
|
||||
ASSUME(gMovesInfo[MOVE_SUCKER_PUNCH].priority == 1);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(300); Moves(MOVE_QUICK_ATTACK); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(100); Moves(MOVE_SUCKER_PUNCH, MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_QUICK_ATTACK); EXPECT_MOVE(opponent, MOVE_SUCKER_PUNCH); }
|
||||
TURN { MOVE(player, MOVE_QUICK_ATTACK); EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,119 +4,139 @@
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_BRICK_BREAK) == EFFECT_BRICK_BREAK);
|
||||
ASSUME(GetMoveEffect(MOVE_PSYCHIC_FANGS) == EFFECT_BRICK_BREAK);
|
||||
ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE);
|
||||
ASSUME(GetMoveEffect(MOVE_LIGHT_SCREEN) == EFFECT_LIGHT_SCREEN);
|
||||
ASSUME(GetMoveEffect(MOVE_REFLECT) == EFFECT_REFLECT);
|
||||
ASSUME(GetMoveEffect(MOVE_AURORA_VEIL) == EFFECT_AURORA_VEIL);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Brick Break removes Light Screen, Reflect and Aurora Veil from the target's side of the field")
|
||||
SINGLE_BATTLE_TEST("Brick Break and Psychic Fangs remove Light Screen, Reflect and Aurora Veil from the target's side of the field")
|
||||
{
|
||||
u16 move;
|
||||
u32 move;
|
||||
u32 breakingMove;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNOWSCAPE); }
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_BRICK_BREAK); }
|
||||
TURN { MOVE(opponent, move); MOVE(player, breakingMove); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, breakingMove, player);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Brick Break doesn't remove Light Screen, Reflect and Aurora Veil if the target is immune")
|
||||
SINGLE_BATTLE_TEST("Brick Break and Psychic Fangs don't remove Light Screen, Reflect and Aurora Veil if the target is immune")
|
||||
{
|
||||
u16 move;
|
||||
u32 move;
|
||||
u32 breakingMove;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GASTLY);
|
||||
OPPONENT(SPECIES_SABLEYE);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNOWSCAPE); }
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_BRICK_BREAK); }
|
||||
TURN { MOVE(opponent, move); MOVE(player, breakingMove); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, breakingMove, player);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Brick Break doesn't remove Light Screen, Reflect and Aurora Veil if the target Protected")
|
||||
SINGLE_BATTLE_TEST("Brick Break and Psychic Fangs don't remove Light Screen, Reflect and Aurora Veil if the target Protected")
|
||||
{
|
||||
u16 move;
|
||||
u32 move;
|
||||
u32 breakingMove;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNOWSCAPE); MOVE(opponent, move); }
|
||||
TURN { MOVE(player, MOVE_BRICK_BREAK); MOVE(opponent, MOVE_PROTECT); }
|
||||
TURN { MOVE(player, breakingMove); MOVE(opponent, MOVE_PROTECT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, breakingMove, player);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Brick Break doesn't remove Light Screen, Reflect and Aurora Veil if it misses")
|
||||
SINGLE_BATTLE_TEST("Brick Break and Psychic Fangs don't remove Light Screen, Reflect and Aurora Veil if it misses")
|
||||
{
|
||||
u16 move;
|
||||
u32 move;
|
||||
u32 breakingMove;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BRIGHT_POWDER); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNOWSCAPE); MOVE(opponent, move); }
|
||||
TURN { MOVE(player, MOVE_BRICK_BREAK, hit: FALSE); }
|
||||
TURN { MOVE(player, breakingMove, hit: FALSE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, breakingMove, player);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Brick Break can remove Light Screen, Reflect and Aurora Veil on users side")
|
||||
DOUBLE_BATTLE_TEST("Brick Break and Psychic Fangs can remove Light Screen, Reflect and Aurora Veil on users side")
|
||||
{
|
||||
u16 move;
|
||||
u32 move;
|
||||
u32 breakingMove;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_BRICK_BREAK; }
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; breakingMove = MOVE_PSYCHIC_FANGS; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
@ -127,12 +147,12 @@ DOUBLE_BATTLE_TEST("Brick Break can remove Light Screen, Reflect and Aurora Veil
|
||||
TURN {
|
||||
MOVE(opponentLeft, MOVE_SNOWSCAPE);
|
||||
MOVE(playerLeft, move);
|
||||
MOVE(playerRight, MOVE_BRICK_BREAK, target: playerLeft);
|
||||
MOVE(playerRight, breakingMove, target: playerLeft);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, breakingMove, playerRight);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(playerLeft);
|
||||
}
|
||||
|
||||
@ -15,7 +15,9 @@ SINGLE_BATTLE_TEST("Curse lowers Speed, raises Attack, and raises Defense when u
|
||||
TURN { MOVE(player, MOVE_CURSE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CURSE, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Wobbuffet's Speed fell!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Wobbuffet's Attack rose!");
|
||||
MESSAGE("Wobbuffet's Defense rose!");
|
||||
}
|
||||
|
||||
71
test/battle/move_effect/follow_me.c
Normal file
71
test/battle/move_effect/follow_me.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_FOLLOW_ME].effect == EFFECT_FOLLOW_ME);
|
||||
ASSUME(gMovesInfo[MOVE_SPOTLIGHT].effect == EFFECT_FOLLOW_ME);
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Follow Me redirects single target moves used by opponents to user")
|
||||
{
|
||||
struct BattlePokemon *moveUser = NULL;
|
||||
struct BattlePokemon *partner = NULL;
|
||||
PARAMETRIZE { moveUser = opponentLeft; partner = opponentRight; }
|
||||
PARAMETRIZE { moveUser = opponentRight; partner = opponentLeft; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_TACKLE, target: moveUser);
|
||||
MOVE(playerRight, MOVE_TACKLE, target: partner);
|
||||
MOVE(moveUser, MOVE_FOLLOW_ME);
|
||||
MOVE(partner, MOVE_TACKLE, target: playerLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOLLOW_ME, moveUser);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft);
|
||||
HP_BAR(moveUser);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
|
||||
HP_BAR(moveUser);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, partner);
|
||||
HP_BAR(playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Spotlight redirects single target moves used by the opposing side to Spotlight's target")
|
||||
{
|
||||
struct BattlePokemon *moveTarget = NULL;
|
||||
PARAMETRIZE { moveTarget = playerRight; }
|
||||
PARAMETRIZE { moveTarget = opponentLeft; }
|
||||
PARAMETRIZE { moveTarget = opponentRight; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_SPOTLIGHT, target: moveTarget);
|
||||
MOVE(playerRight, MOVE_TACKLE, target: opponentRight);
|
||||
MOVE(opponentLeft, MOVE_TACKLE, target: playerLeft);
|
||||
MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPOTLIGHT, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
|
||||
if (moveTarget != playerRight)
|
||||
HP_BAR(moveTarget);
|
||||
else
|
||||
HP_BAR(opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft);
|
||||
if (moveTarget == playerRight)
|
||||
HP_BAR(moveTarget);
|
||||
else
|
||||
HP_BAR(playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight);
|
||||
if (moveTarget == playerRight)
|
||||
HP_BAR(moveTarget);
|
||||
else
|
||||
HP_BAR(playerLeft);
|
||||
}
|
||||
}
|
||||
@ -217,8 +217,11 @@ DOUBLE_BATTLE_TEST("Instruct-called moves keep their priority")
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Instructed move will be absorbed by Lightning Rod if it turns into an Electric Type move")
|
||||
DOUBLE_BATTLE_TEST("Instructed move will be redirected and absorbed by Lightning Rod if it turns into an Electric Type move")
|
||||
{
|
||||
struct BattlePokemon *moveTarget = NULL;
|
||||
PARAMETRIZE { moveTarget = opponentLeft; }
|
||||
PARAMETRIZE { moveTarget = opponentRight; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
@ -226,7 +229,7 @@ DOUBLE_BATTLE_TEST("Instructed move will be absorbed by Lightning Rod if it turn
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft);
|
||||
MOVE(playerLeft, MOVE_TACKLE, target: moveTarget);
|
||||
MOVE(opponentLeft, MOVE_PLASMA_FISTS, target: playerLeft);
|
||||
MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft);
|
||||
MOVE(opponentRight, MOVE_CELEBRATE);
|
||||
@ -239,3 +242,65 @@ DOUBLE_BATTLE_TEST("Instructed move will be absorbed by Lightning Rod if it turn
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Instructed move will be redirected by Follow Me after instructed target loses Stalwart")
|
||||
{
|
||||
struct BattlePokemon *moveTarget = NULL;
|
||||
PARAMETRIZE { moveTarget = opponentLeft; }
|
||||
PARAMETRIZE { moveTarget = opponentRight; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_FOLLOW_ME].effect == EFFECT_FOLLOW_ME);
|
||||
ASSUME(gMovesInfo[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP);
|
||||
PLAYER(SPECIES_DURALUDON) { Ability(ABILITY_STALWART); }
|
||||
PLAYER(SPECIES_DURALUDON) { Ability(ABILITY_STALWART); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerLeft, MOVE_TACKLE, target: moveTarget);
|
||||
MOVE(opponentLeft, MOVE_FOLLOW_ME);
|
||||
MOVE(opponentRight, MOVE_SKILL_SWAP, target: playerLeft);
|
||||
MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOLLOW_ME, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft);
|
||||
HP_BAR(moveTarget);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Instructed move will be redirected by Rage Powder after instructed target loses Grass typing")
|
||||
{
|
||||
struct BattlePokemon *moveTarget = NULL;
|
||||
PARAMETRIZE { moveTarget = opponentLeft; }
|
||||
PARAMETRIZE { moveTarget = opponentRight; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_RAGE_POWDER].effect == EFFECT_FOLLOW_ME);
|
||||
ASSUME(gMovesInfo[MOVE_RAGE_POWDER].powderMove == TRUE);
|
||||
ASSUME(gMovesInfo[MOVE_SOAK].effect == EFFECT_SOAK);
|
||||
PLAYER(SPECIES_TREECKO);
|
||||
PLAYER(SPECIES_SCEPTILE);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerLeft, MOVE_TACKLE, target: moveTarget);
|
||||
MOVE(opponentLeft, MOVE_RAGE_POWDER);
|
||||
MOVE(opponentRight, MOVE_SOAK, target: playerLeft);
|
||||
MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAGE_POWDER, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft);
|
||||
HP_BAR(moveTarget);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SOAK, opponentRight);
|
||||
MESSAGE("Treecko transformed into the Water type!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,6 @@ SINGLE_BATTLE_TEST("Raging Bull doesn't remove Light Screen, Reflect and Aurora
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GASTLY);
|
||||
|
||||
98
test/battle/move_effect/rototiller.c
Normal file
98
test/battle/move_effect/rototiller.c
Normal file
@ -0,0 +1,98 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_ROTOTILLER].effect == EFFECT_ROTOTILLER);
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Rototiller boosts Attack and Special Attack of all Grass types on the field")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_TANGELA].types[0] == TYPE_GRASS);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SNIVY].types[0] == TYPE_GRASS);
|
||||
PLAYER(SPECIES_TANGELA);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_SNIVY);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_ROTOTILLER); MOVE(playerLeft, MOVE_CELEBRATE); MOVE(opponentLeft, MOVE_CELEBRATE); MOVE(opponentRight, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROTOTILLER, playerRight);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
} THEN {
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(playerRight->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Rototiller fails if there are no valid targets")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_GRASS);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_GRASS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROTOTILLER); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_ROTOTILLER, player);
|
||||
MESSAGE("Wobbuffet used Rototiller!");
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Rototiller doesn't affect pokemon that are semi-invulnerable")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_TANGELA].types[0] == TYPE_GRASS);
|
||||
ASSUME(gMovesInfo[MOVE_DIG].effect == EFFECT_SEMI_INVULNERABLE);
|
||||
PLAYER(SPECIES_TANGELA);
|
||||
OPPONENT(SPECIES_TANGELA);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_DIG); MOVE(player, MOVE_ROTOTILLER); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DIG, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROTOTILLER, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("It won't have any effect on the opposing Tangela!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Rototiller fails if the only valid target is semi-invulnerable")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_TANGELA].types[0] == TYPE_GRASS);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_GRASS);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_GRASS);
|
||||
ASSUME(gMovesInfo[MOVE_DIG].effect == EFFECT_SEMI_INVULNERABLE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_TANGELA);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_DIG); MOVE(player, MOVE_ROTOTILLER); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DIG, opponent);
|
||||
MESSAGE("Wobbuffet used Rototiller!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_ROTOTILLER, player);
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
@ -32,7 +32,6 @@ SINGLE_BATTLE_TEST("Sleep Talk fails if not asleep")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SINGLE_BATTLE_TEST("Sleep Talk works if user has Comatose")
|
||||
{
|
||||
|
||||
@ -91,3 +90,59 @@ SINGLE_BATTLE_TEST("Sleep Talk can use moves while choiced into Sleep Talk")
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sleep Talk fails if user is taunted")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TAUNT].effect == EFFECT_TAUNT);
|
||||
ASSUME(gMovesInfo[MOVE_SLEEP_TALK].category == DAMAGE_CATEGORY_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_TACKLE, MOVE_FLY, MOVE_DIG); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TAUNT); MOVE(player, MOVE_SLEEP_TALK); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SLEEP_TALK, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sleep Talk calls move and that move may be redirected by Lightning Rod")
|
||||
{
|
||||
PASSES_RANDOMLY(1, 2, RNG_RANDOM_TARGET);
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SPARK].type == TYPE_ELECTRIC);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_SPARK, MOVE_FLY, MOVE_DIG); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_SLEEP_TALK); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SLEEP_TALK, playerLeft);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARK, playerLeft);
|
||||
MESSAGE("The opposing Raichu's Lightning Rod took the attack!");
|
||||
ABILITY_POPUP(opponentRight, ABILITY_LIGHTNING_ROD);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sleep Talk calls move and that move may be redirected by Storm Drain")
|
||||
{
|
||||
PASSES_RANDOMLY(1, 2, RNG_RANDOM_TARGET);
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_WATER_GUN, MOVE_FLY, MOVE_DIG); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GASTRODON) { Ability(ABILITY_STORM_DRAIN); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_SLEEP_TALK); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SLEEP_TALK, playerLeft);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerLeft);
|
||||
MESSAGE("The opposing Gastrodon's Storm Drain took the attack!");
|
||||
ABILITY_POPUP(opponentRight, ABILITY_STORM_DRAIN);
|
||||
}
|
||||
}
|
||||
|
||||
59
test/battle/move_effect/snore.c
Normal file
59
test/battle/move_effect/snore.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_SNORE].effect == EFFECT_SNORE);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Snore fails if not asleep")
|
||||
{
|
||||
u32 status;
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_NONE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNORE); }
|
||||
} SCENE {
|
||||
if (status == STATUS1_SLEEP) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNORE, player);
|
||||
NOT MESSAGE("But it failed!");
|
||||
}
|
||||
else {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SNORE, player);
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Snore works if user has Comatose")
|
||||
{
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KOMALA);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNORE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNORE, player);
|
||||
NOT MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Snore fails if user is throat chopped")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP));
|
||||
ASSUME(gMovesInfo[MOVE_SNORE].soundMove == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_THROAT_CHOP); MOVE(player, MOVE_SNORE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THROAT_CHOP, opponent);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SNORE, player);
|
||||
}
|
||||
}
|
||||
@ -62,3 +62,18 @@ AI_SINGLE_BATTLE_TEST("AI avoids Thunder Wave when it can not paralyse target")
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_THUNDER_WAVE); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Thunder Wave doesn't affect Electric types in Gen6+")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_PIKACHU].types[0] == TYPE_ELECTRIC);
|
||||
ASSUME(B_PARALYZE_ELECTRIC >= GEN_6);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIKACHU);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THUNDER_WAVE); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Thunder Wave!");
|
||||
MESSAGE("It doesn't affect the opposing Pikachu…");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user