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
|
printstring STRINGID_ATTACKERMELTEDTHEICE
|
||||||
goto BattleScript_AffectionBasedStatusHeal_Continue
|
goto BattleScript_AffectionBasedStatusHeal_Continue
|
||||||
BattleScript_AffectionBasedStatus_HealFrostbiteString:
|
BattleScript_AffectionBasedStatus_HealFrostbiteString:
|
||||||
printstring STRINGID_ATTACKERMELTEDTHEICE
|
printstring STRINGID_ATTACKERHEALEDITSFROSTBITE
|
||||||
BattleScript_AffectionBasedStatusHeal_Continue:
|
BattleScript_AffectionBasedStatusHeal_Continue:
|
||||||
waitmessage B_WAIT_TIME_LONG
|
waitmessage B_WAIT_TIME_LONG
|
||||||
clearstatus BS_ATTACKER
|
clearstatus BS_ATTACKER
|
||||||
@ -1563,6 +1563,7 @@ BattleScript_RototillerMoveTargetEnd:
|
|||||||
moveendto MOVEEND_NEXT_TARGET
|
moveendto MOVEEND_NEXT_TARGET
|
||||||
addbyte gBattlerTarget, 1
|
addbyte gBattlerTarget, 1
|
||||||
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_RototillerLoop
|
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_RototillerLoop
|
||||||
|
restoretarget
|
||||||
end
|
end
|
||||||
|
|
||||||
BattleScript_RototillerCantRaiseMultipleStats:
|
BattleScript_RototillerCantRaiseMultipleStats:
|
||||||
@ -1743,8 +1744,6 @@ BattleScript_EffectCopycat::
|
|||||||
trycopycat BattleScript_CopycatFail
|
trycopycat BattleScript_CopycatFail
|
||||||
attackanimation
|
attackanimation
|
||||||
waitanimation
|
waitanimation
|
||||||
setbyte sB_ANIM_TURN, 0
|
|
||||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
|
||||||
jumptocalledmove TRUE
|
jumptocalledmove TRUE
|
||||||
BattleScript_CopycatFail:
|
BattleScript_CopycatFail:
|
||||||
ppreduce
|
ppreduce
|
||||||
@ -1762,8 +1761,6 @@ BattleScript_EffectInstruct::
|
|||||||
copybyte gBattlerTarget, gEffectBattler
|
copybyte gBattlerTarget, gEffectBattler
|
||||||
printstring STRINGID_USEDINSTRUCTEDMOVE
|
printstring STRINGID_USEDINSTRUCTEDMOVE
|
||||||
waitmessage B_WAIT_TIME_LONG
|
waitmessage B_WAIT_TIME_LONG
|
||||||
setbyte sB_ANIM_TURN, 0
|
|
||||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
|
||||||
jumptocalledmove TRUE
|
jumptocalledmove TRUE
|
||||||
|
|
||||||
BattleScript_EffectAutotomize::
|
BattleScript_EffectAutotomize::
|
||||||
@ -2187,8 +2184,6 @@ BattleScript_EffectMeFirst::
|
|||||||
trymefirst BattleScript_FailedFromPpReduce
|
trymefirst BattleScript_FailedFromPpReduce
|
||||||
attackanimation
|
attackanimation
|
||||||
waitanimation
|
waitanimation
|
||||||
setbyte sB_ANIM_TURN, 0
|
|
||||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
|
||||||
jumptocalledmove TRUE
|
jumptocalledmove TRUE
|
||||||
|
|
||||||
BattleScript_EffectAttackSpAttackUp::
|
BattleScript_EffectAttackSpAttackUp::
|
||||||
@ -3657,12 +3652,12 @@ BattleScript_EffectParalyze::
|
|||||||
jumpifmovehadnoeffect BattleScript_ButItFailed
|
jumpifmovehadnoeffect BattleScript_ButItFailed
|
||||||
jumpifstatus BS_TARGET, STATUS1_PARALYSIS, BattleScript_AlreadyParalyzed
|
jumpifstatus BS_TARGET, STATUS1_PARALYSIS, BattleScript_AlreadyParalyzed
|
||||||
jumpifelectricabilityaffected BS_TARGET, ABILITY_VOLT_ABSORB, BattleScript_VoltAbsorbHeal
|
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
|
tryparalyzetype BS_ATTACKER, BS_TARGET, BattleScript_NotAffected
|
||||||
jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed
|
jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed
|
||||||
jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents
|
jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents
|
||||||
accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE
|
accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE
|
||||||
jumpifsafeguard BattleScript_SafeguardProtected
|
jumpifsafeguard BattleScript_SafeguardProtected
|
||||||
clearmoveresultflags MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE
|
|
||||||
attackanimation
|
attackanimation
|
||||||
waitanimation
|
waitanimation
|
||||||
seteffectprimary MOVE_EFFECT_PARALYSIS
|
seteffectprimary MOVE_EFFECT_PARALYSIS
|
||||||
@ -3843,8 +3838,6 @@ BattleScript_EffectMetronome::
|
|||||||
pause B_WAIT_TIME_SHORT
|
pause B_WAIT_TIME_SHORT
|
||||||
attackanimation
|
attackanimation
|
||||||
waitanimation
|
waitanimation
|
||||||
setbyte sB_ANIM_TURN, 0
|
|
||||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
|
||||||
metronome
|
metronome
|
||||||
|
|
||||||
BattleScript_EffectLeechSeed::
|
BattleScript_EffectLeechSeed::
|
||||||
@ -4051,8 +4044,6 @@ BattleScript_SleepTalkIsAsleep::
|
|||||||
BattleScript_SleepTalkUsingMove::
|
BattleScript_SleepTalkUsingMove::
|
||||||
attackanimation
|
attackanimation
|
||||||
waitanimation
|
waitanimation
|
||||||
setbyte sB_ANIM_TURN, 0
|
|
||||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
|
||||||
jumptocalledmove TRUE
|
jumptocalledmove TRUE
|
||||||
|
|
||||||
BattleScript_EffectDestinyBond::
|
BattleScript_EffectDestinyBond::
|
||||||
@ -4167,11 +4158,15 @@ BattleScript_CurseTrySpeed::
|
|||||||
setbyte sB_ANIM_TURN, 1
|
setbyte sB_ANIM_TURN, 1
|
||||||
attackanimation
|
attackanimation
|
||||||
waitanimation
|
waitanimation
|
||||||
|
setbyte sSTAT_ANIM_PLAYED, FALSE
|
||||||
|
playstatchangeanimation BS_ATTACKER, BIT_SPEED, STAT_CHANGE_NEGATIVE
|
||||||
setstatchanger STAT_SPEED, 1, TRUE
|
setstatchanger STAT_SPEED, 1, TRUE
|
||||||
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CurseTryAttack
|
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CurseTryAttack
|
||||||
printfromtable gStatDownStringIds
|
printfromtable gStatDownStringIds
|
||||||
waitmessage B_WAIT_TIME_LONG
|
waitmessage B_WAIT_TIME_LONG
|
||||||
BattleScript_CurseTryAttack::
|
BattleScript_CurseTryAttack::
|
||||||
|
setbyte sSTAT_ANIM_PLAYED, FALSE
|
||||||
|
playstatchangeanimation BS_ATTACKER, BIT_ATK | BIT_DEF, 0
|
||||||
setstatchanger STAT_ATK, 1, FALSE
|
setstatchanger STAT_ATK, 1, FALSE
|
||||||
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CurseTryDefense
|
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CurseTryDefense
|
||||||
printfromtable gStatUpStringIds
|
printfromtable gStatUpStringIds
|
||||||
@ -5070,8 +5065,6 @@ BattleScript_EffectAssist::
|
|||||||
assistattackselect BattleScript_FailedFromPpReduce
|
assistattackselect BattleScript_FailedFromPpReduce
|
||||||
attackanimation
|
attackanimation
|
||||||
waitanimation
|
waitanimation
|
||||||
setbyte sB_ANIM_TURN, 0
|
|
||||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
|
||||||
jumptocalledmove TRUE
|
jumptocalledmove TRUE
|
||||||
|
|
||||||
BattleScript_EffectIngrain::
|
BattleScript_EffectIngrain::
|
||||||
@ -5112,6 +5105,7 @@ BattleScript_EffectBrickBreak::
|
|||||||
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
||||||
attackstring
|
attackstring
|
||||||
ppreduce
|
ppreduce
|
||||||
|
typecalc
|
||||||
removelightscreenreflect
|
removelightscreenreflect
|
||||||
critcalc
|
critcalc
|
||||||
damagecalc
|
damagecalc
|
||||||
@ -8651,8 +8645,6 @@ BattleScript_BattleBondActivatesOnMoveEndAttacker::
|
|||||||
BattleScript_DancerActivates::
|
BattleScript_DancerActivates::
|
||||||
call BattleScript_AbilityPopUp
|
call BattleScript_AbilityPopUp
|
||||||
waitmessage B_WAIT_TIME_SHORT
|
waitmessage B_WAIT_TIME_SHORT
|
||||||
setbyte sB_ANIM_TURN, 0
|
|
||||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
|
||||||
orword gHitMarker, HITMARKER_ALLOW_NO_PP
|
orword gHitMarker, HITMARKER_ALLOW_NO_PP
|
||||||
jumptocalledmove TRUE
|
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);
|
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 Command Reference
|
||||||
|
|
||||||
### `OVERWORLD_SCRIPT`
|
### `OVERWORLD_SCRIPT`
|
||||||
|
|||||||
@ -14,6 +14,6 @@ JASC-PAL
|
|||||||
96 168 120
|
96 168 120
|
||||||
64 136 96
|
64 136 96
|
||||||
232 232 248
|
232 232 248
|
||||||
152 40 64
|
39 44 149
|
||||||
0 0 0
|
0 0 0
|
||||||
0 0 0
|
0 0 0
|
||||||
|
|||||||
@ -835,6 +835,7 @@ struct BattleStruct
|
|||||||
u8 padding3:2;
|
u8 padding3:2;
|
||||||
struct MessageStatus slideMessageStatus;
|
struct MessageStatus slideMessageStatus;
|
||||||
u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT];
|
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,
|
// 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);
|
void HandleAction_ThrowBall(void);
|
||||||
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move);
|
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move);
|
||||||
|
bool32 HandleMoveTargetRedirection(void);
|
||||||
void HandleAction_UseMove(void);
|
void HandleAction_UseMove(void);
|
||||||
void HandleAction_Switch(void);
|
void HandleAction_Switch(void);
|
||||||
void HandleAction_UseItem(void);
|
void HandleAction_UseItem(void);
|
||||||
|
|||||||
@ -533,6 +533,20 @@ static inline s32 SetFixedMoveBasePower(u32 battlerAtk, u32 move)
|
|||||||
return fixedBasePower;
|
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)
|
static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCalcData, s32 *expectedDamage, s32 *minimumDamage, u32 holdEffectAtk, u32 abilityAtk)
|
||||||
{
|
{
|
||||||
u32 move = damageCalcData->move;
|
u32 move = damageCalcData->move;
|
||||||
@ -658,6 +672,9 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
|||||||
{
|
{
|
||||||
s32 critChanceIndex, fixedBasePower;
|
s32 critChanceIndex, fixedBasePower;
|
||||||
|
|
||||||
|
u32 types[3];
|
||||||
|
AI_StoreBattlerTypes(battlerAtk, types);
|
||||||
|
|
||||||
ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, moveType);
|
ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, moveType);
|
||||||
fixedBasePower = SetFixedMoveBasePower(battlerAtk, move);
|
fixedBasePower = SetFixedMoveBasePower(battlerAtk, move);
|
||||||
|
|
||||||
@ -735,6 +752,8 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
|||||||
aiData->holdEffects[battlerAtk],
|
aiData->holdEffects[battlerAtk],
|
||||||
aiData->abilities[battlerAtk]);
|
aiData->abilities[battlerAtk]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AI_RestoreBattlerTypes(battlerAtk, types);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1068,8 +1087,15 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 moveConsidered)
|
|||||||
u32 abilityAI = AI_DATA->abilities[battlerAI];
|
u32 abilityAI = AI_DATA->abilities[battlerAI];
|
||||||
u32 abilityPlayer = AI_DATA->abilities[battler];
|
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;
|
return AI_IS_FASTER;
|
||||||
|
else if (aiPriority < playerPriority)
|
||||||
|
return AI_IS_SLOWER;
|
||||||
|
|
||||||
speedBattlerAI = GetBattlerTotalSpeedStatArgs(battlerAI, abilityAI, holdEffectAI);
|
speedBattlerAI = GetBattlerTotalSpeedStatArgs(battlerAI, abilityAI, holdEffectAI);
|
||||||
speedBattler = GetBattlerTotalSpeedStatArgs(battler, abilityPlayer, holdEffectPlayer);
|
speedBattler = GetBattlerTotalSpeedStatArgs(battler, abilityPlayer, holdEffectPlayer);
|
||||||
|
|||||||
@ -344,6 +344,7 @@ static bool8 CanBurnHitThaw(u16 move);
|
|||||||
static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent);
|
static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent);
|
||||||
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove);
|
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove);
|
||||||
static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move);
|
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_attackcanceler(void);
|
||||||
static void Cmd_accuracycheck(void);
|
static void Cmd_accuracycheck(void);
|
||||||
@ -8746,6 +8747,18 @@ static void Cmd_hidepartystatussummary(void)
|
|||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
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)
|
static void Cmd_jumptocalledmove(void)
|
||||||
{
|
{
|
||||||
CMD_ARGS(bool8 notChosenMove);
|
CMD_ARGS(bool8 notChosenMove);
|
||||||
@ -8755,6 +8768,8 @@ static void Cmd_jumptocalledmove(void)
|
|||||||
else
|
else
|
||||||
gChosenMove = gCurrentMove = gCalledMove;
|
gChosenMove = gCurrentMove = gCalledMove;
|
||||||
|
|
||||||
|
ResetValuesForCalledMove();
|
||||||
|
|
||||||
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10811,10 +10826,8 @@ static void Cmd_various(void)
|
|||||||
gBattlescriptCurrInstr = cmd->failInstr;
|
gBattlescriptCurrInstr = cmd->failInstr;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetTypeBeforeUsingMove(gCalledMove, gBattlerTarget);
|
|
||||||
gEffectBattler = gBattleStruct->lastMoveTarget[gBattlerTarget];
|
gEffectBattler = gBattleStruct->lastMoveTarget[gBattlerTarget];
|
||||||
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
|
||||||
gBattleStruct->atkCancellerTracker = 0;
|
|
||||||
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, battler, gBattlerPartyIndexes[battler]);
|
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, battler, gBattlerPartyIndexes[battler]);
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
}
|
}
|
||||||
@ -11804,8 +11817,8 @@ static void SetMoveForMirrorMove(u32 move)
|
|||||||
gCurrentMove = move;
|
gCurrentMove = move;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAtkCancellerForCalledMove();
|
|
||||||
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||||
|
ResetValuesForCalledMove();
|
||||||
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13333,10 +13346,10 @@ static void Cmd_metronome(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
gCurrentMove = RandomUniformExcept(RNG_METRONOME, 1, moveCount - 1, InvalidMetronomeMove);
|
gCurrentMove = RandomUniformExcept(RNG_METRONOME, 1, moveCount - 1, InvalidMetronomeMove);
|
||||||
SetAtkCancellerForCalledMove();
|
|
||||||
PrepareStringBattle(STRINGID_WAGGLINGAFINGER, gBattlerAttacker);
|
PrepareStringBattle(STRINGID_WAGGLINGAFINGER, gBattlerAttacker);
|
||||||
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove);
|
||||||
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||||
|
ResetValuesForCalledMove();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Cmd_dmgtolevel(void)
|
static void Cmd_dmgtolevel(void)
|
||||||
@ -18046,14 +18059,10 @@ void BS_JumpIfBlockedBySoundproof(void)
|
|||||||
void BS_SetMagicCoatTarget(void)
|
void BS_SetMagicCoatTarget(void)
|
||||||
{
|
{
|
||||||
NATIVE_ARGS();
|
NATIVE_ARGS();
|
||||||
u32 side;
|
|
||||||
gBattleStruct->attackerBeforeBounce = gBattleScripting.battler = gBattlerAttacker;
|
gBattleStruct->attackerBeforeBounce = gBattleScripting.battler = gBattlerAttacker;
|
||||||
gBattlerAttacker = gBattlerTarget;
|
gBattlerAttacker = gBattlerTarget;
|
||||||
side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker));
|
gBattlerTarget = gBattleStruct->attackerBeforeBounce;
|
||||||
if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove))
|
HandleMoveTargetRedirection();
|
||||||
gBattlerTarget = gSideTimers[side].followmeTarget;
|
|
||||||
else
|
|
||||||
gBattlerTarget = gBattleStruct->attackerBeforeBounce;
|
|
||||||
|
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -234,11 +234,69 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move)
|
|||||||
return TRUE;
|
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
|
// Functions
|
||||||
void HandleAction_UseMove(void)
|
void HandleAction_UseMove(void)
|
||||||
{
|
{
|
||||||
u32 battler, i, side, moveType, ability, var = MAX_BATTLERS_COUNT;
|
u32 i;
|
||||||
u16 moveTarget;
|
|
||||||
|
|
||||||
gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber];
|
gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber];
|
||||||
if (gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags
|
if (gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags
|
||||||
@ -308,7 +366,6 @@ void HandleAction_UseMove(void)
|
|||||||
|
|
||||||
// Set dynamic move type.
|
// Set dynamic move type.
|
||||||
SetTypeBeforeUsingMove(gChosenMove, gBattlerAttacker);
|
SetTypeBeforeUsingMove(gChosenMove, gBattlerAttacker);
|
||||||
moveType = GetBattleMoveType(gCurrentMove);
|
|
||||||
|
|
||||||
// check Z-Move used
|
// check Z-Move used
|
||||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gCurrentMove) && !IsZMove(gCurrentMove))
|
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gCurrentMove) && !IsZMove(gCurrentMove))
|
||||||
@ -323,117 +380,44 @@ void HandleAction_UseMove(void)
|
|||||||
gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove);
|
gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
|
if (!HandleMoveTargetRedirection())
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = gSideTimers[side].followmeTarget; // follow me moxie fix
|
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
|
||||||
}
|
if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM)
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
ability = GetBattlerAbility(battler);
|
gBattlerTarget = SetRandomTarget(gBattlerAttacker);
|
||||||
if ((B_REDIRECT_ABILITY_ALLIES >= GEN_4 || !IsBattlerAlly(gBattlerAttacker, battler))
|
if (gAbsentBattlerFlags & (1u << gBattlerTarget)
|
||||||
&& battler != gBattlerAttacker
|
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget))
|
||||||
&& 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 = GetPartnerBattler(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
|
else
|
||||||
{
|
{
|
||||||
u16 battlerAbility;
|
gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker);
|
||||||
battler = gBattlerByTurnOrder[var];
|
if (!IsBattlerAlive(gBattlerTarget)
|
||||||
battlerAbility = GetBattlerAbility(battler);
|
&& moveTarget != MOVE_TARGET_OPPONENTS_FIELD
|
||||||
|
&& (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)))
|
||||||
RecordAbilityBattle(battler, gBattleMons[battler].ability);
|
{
|
||||||
if (battlerAbility == ABILITY_LIGHTNING_ROD && gCurrentMove != MOVE_TEATIME)
|
gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget)));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3215,6 +3199,8 @@ static void CancellerAsleep(u32 *effect)
|
|||||||
gBattleMons[gBattlerAttacker].status1 -= toSub;
|
gBattleMons[gBattlerAttacker].status1 -= toSub;
|
||||||
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
|
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)
|
if (gChosenMove != MOVE_SNORE && gChosenMove != MOVE_SLEEP_TALK)
|
||||||
{
|
{
|
||||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep;
|
gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep;
|
||||||
@ -3551,7 +3537,7 @@ static void CancellerThaw(u32 *effect)
|
|||||||
|
|
||||||
static void CancellerStanceChangeTwo(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;
|
*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_HEARTHFLAME_MASK:
|
||||||
case ABILITY_EMBODY_ASPECT_WELLSPRING_MASK:
|
case ABILITY_EMBODY_ASPECT_WELLSPRING_MASK:
|
||||||
case ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK:
|
case ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK:
|
||||||
if (!gSpecialStatuses[battler].switchInAbilityDone)
|
if (!gSpecialStatuses[battler].switchInAbilityDone
|
||||||
|
&& !(gBattleStruct->embodyAspectBoost[GetBattlerSide(battler)] & (1u << gBattlerPartyIndexes[battler])))
|
||||||
{
|
{
|
||||||
u32 stat;
|
u32 stat;
|
||||||
|
|
||||||
@ -5325,6 +5312,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
|||||||
gBattleScripting.savedBattler = gBattlerAttacker;
|
gBattleScripting.savedBattler = gBattlerAttacker;
|
||||||
gBattlerAttacker = battler;
|
gBattlerAttacker = battler;
|
||||||
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
|
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
|
||||||
|
gBattleStruct->embodyAspectBoost[GetBattlerSide(battler)] |= 1u << gBattlerPartyIndexes[battler];
|
||||||
SET_STATCHANGER(stat, 1, FALSE);
|
SET_STATCHANGER(stat, 1, FALSE);
|
||||||
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
|
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
|
||||||
effect++;
|
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
|
// Set bit and save Dancer mon's original target
|
||||||
gSpecialStatuses[battler].dancerUsedMove = TRUE;
|
gSpecialStatuses[battler].dancerUsedMove = TRUE;
|
||||||
gSpecialStatuses[battler].dancerOriginalTarget = gBattleStruct->moveTarget[battler] | 0x4;
|
gSpecialStatuses[battler].dancerOriginalTarget = gBattleStruct->moveTarget[battler] | 0x4;
|
||||||
gBattleStruct->atkCancellerTracker = 0;
|
|
||||||
gBattlerAttacker = gBattlerAbility = battler;
|
gBattlerAttacker = gBattlerAbility = battler;
|
||||||
gCalledMove = gCurrentMove;
|
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
|
// Edge case for dance moves that hit multiply targets
|
||||||
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
|
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
|
||||||
SetTypeBeforeUsingMove(gCalledMove, battler);
|
|
||||||
|
|
||||||
// Make sure that the target isn't an ally - if it is, target the original user
|
// Make sure that the target isn't an ally - if it is, target the original user
|
||||||
if (IsBattlerAlly(gBattlerTarget, gBattlerAttacker))
|
if (IsBattlerAlly(gBattlerTarget, gBattlerAttacker))
|
||||||
|
|||||||
@ -105,7 +105,7 @@ static const u8 sFeintDescription[] = _(
|
|||||||
"An attack that hits foes\n"
|
"An attack that hits foes\n"
|
||||||
"using moves like Protect.");
|
"using moves like Protect.");
|
||||||
|
|
||||||
const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||||
{
|
{
|
||||||
[MOVE_NONE] =
|
[MOVE_NONE] =
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3439,7 +3439,7 @@ static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId) //https://githu
|
|||||||
//Moves
|
//Moves
|
||||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
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;
|
continue;
|
||||||
|
|
||||||
SetMonMoveSlot(&mon, moves[i], i);
|
SetMonMoveSlot(&mon, moves[i], i);
|
||||||
|
|||||||
@ -38,8 +38,6 @@ static void Task_DrawFieldMessage(u8 taskId)
|
|||||||
LoadMessageBoxAndBorderGfx();
|
LoadMessageBoxAndBorderGfx();
|
||||||
task->tState++;
|
task->tState++;
|
||||||
break;
|
break;
|
||||||
task->tState++;
|
|
||||||
break;
|
|
||||||
case 1:
|
case 1:
|
||||||
DrawDialogueFrame(0, TRUE);
|
DrawDialogueFrame(0, TRUE);
|
||||||
task->tState++;
|
task->tState++;
|
||||||
|
|||||||
@ -6074,15 +6074,8 @@ const u8 *GetTrainerPartnerName(void)
|
|||||||
{
|
{
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||||
{
|
{
|
||||||
if (gPartnerTrainerId == TRAINER_PARTNER(PARTNER_STEVEN))
|
GetFrontierTrainerName(gStringVar1, gPartnerTrainerId);
|
||||||
{
|
return gStringVar1;
|
||||||
return GetTrainerNameFromId(PARTNER_STEVEN);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GetFrontierTrainerName(gStringVar1, gPartnerTrainerId);
|
|
||||||
return gStringVar1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
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!");
|
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); }
|
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
|
ASSUMPTIONS
|
||||||
{
|
{
|
||||||
ASSUME(GetMoveEffect(MOVE_BRICK_BREAK) == EFFECT_BRICK_BREAK);
|
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_SNOWSCAPE) == EFFECT_SNOWSCAPE);
|
||||||
ASSUME(GetMoveEffect(MOVE_LIGHT_SCREEN) == EFFECT_LIGHT_SCREEN);
|
ASSUME(GetMoveEffect(MOVE_LIGHT_SCREEN) == EFFECT_LIGHT_SCREEN);
|
||||||
ASSUME(GetMoveEffect(MOVE_REFLECT) == EFFECT_REFLECT);
|
ASSUME(GetMoveEffect(MOVE_REFLECT) == EFFECT_REFLECT);
|
||||||
ASSUME(GetMoveEffect(MOVE_AURORA_VEIL) == EFFECT_AURORA_VEIL);
|
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_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
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 {
|
GIVEN {
|
||||||
PLAYER(SPECIES_WOBBUFFET);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN { MOVE(player, MOVE_SNOWSCAPE); }
|
TURN { MOVE(player, MOVE_SNOWSCAPE); }
|
||||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_BRICK_BREAK); }
|
TURN { MOVE(opponent, move); MOVE(player, breakingMove); }
|
||||||
} SCENE {
|
} SCENE {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
|
ANIMATION(ANIM_TYPE_MOVE, breakingMove, player);
|
||||||
MESSAGE("The wall shattered!");
|
MESSAGE("The wall shattered!");
|
||||||
HP_BAR(opponent);
|
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_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
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 {
|
GIVEN {
|
||||||
PLAYER(SPECIES_WOBBUFFET);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
OPPONENT(SPECIES_GASTLY);
|
OPPONENT(SPECIES_SABLEYE);
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN { MOVE(player, MOVE_SNOWSCAPE); }
|
TURN { MOVE(player, MOVE_SNOWSCAPE); }
|
||||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_BRICK_BREAK); }
|
TURN { MOVE(opponent, move); MOVE(player, breakingMove); }
|
||||||
} SCENE {
|
} SCENE {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||||
NONE_OF {
|
NONE_OF {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
|
ANIMATION(ANIM_TYPE_MOVE, breakingMove, player);
|
||||||
MESSAGE("The wall shattered!");
|
MESSAGE("The wall shattered!");
|
||||||
HP_BAR(opponent);
|
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_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
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 {
|
GIVEN {
|
||||||
PLAYER(SPECIES_WOBBUFFET);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN { MOVE(player, MOVE_SNOWSCAPE); MOVE(opponent, move); }
|
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 {
|
} SCENE {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent);
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent);
|
||||||
NONE_OF {
|
NONE_OF {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
|
ANIMATION(ANIM_TYPE_MOVE, breakingMove, player);
|
||||||
MESSAGE("The wall shattered!");
|
MESSAGE("The wall shattered!");
|
||||||
HP_BAR(opponent);
|
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_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
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 {
|
GIVEN {
|
||||||
PLAYER(SPECIES_WOBBUFFET);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BRIGHT_POWDER); }
|
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BRIGHT_POWDER); }
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN { MOVE(player, MOVE_SNOWSCAPE); MOVE(opponent, move); }
|
TURN { MOVE(player, MOVE_SNOWSCAPE); MOVE(opponent, move); }
|
||||||
TURN { MOVE(player, MOVE_BRICK_BREAK, hit: FALSE); }
|
TURN { MOVE(player, breakingMove, hit: FALSE); }
|
||||||
} SCENE {
|
} SCENE {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||||
NONE_OF {
|
NONE_OF {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, player);
|
ANIMATION(ANIM_TYPE_MOVE, breakingMove, player);
|
||||||
MESSAGE("The wall shattered!");
|
MESSAGE("The wall shattered!");
|
||||||
HP_BAR(opponent);
|
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_LIGHT_SCREEN; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
PARAMETRIZE { move = MOVE_REFLECT; breakingMove = MOVE_BRICK_BREAK; }
|
||||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
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 {
|
GIVEN {
|
||||||
PLAYER(SPECIES_WOBBUFFET);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
@ -127,12 +147,12 @@ DOUBLE_BATTLE_TEST("Brick Break can remove Light Screen, Reflect and Aurora Veil
|
|||||||
TURN {
|
TURN {
|
||||||
MOVE(opponentLeft, MOVE_SNOWSCAPE);
|
MOVE(opponentLeft, MOVE_SNOWSCAPE);
|
||||||
MOVE(playerLeft, move);
|
MOVE(playerLeft, move);
|
||||||
MOVE(playerRight, MOVE_BRICK_BREAK, target: playerLeft);
|
MOVE(playerRight, breakingMove, target: playerLeft);
|
||||||
}
|
}
|
||||||
} SCENE {
|
} SCENE {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, opponentLeft);
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, opponentLeft);
|
||||||
ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
|
ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BRICK_BREAK, playerRight);
|
ANIMATION(ANIM_TYPE_MOVE, breakingMove, playerRight);
|
||||||
MESSAGE("The wall shattered!");
|
MESSAGE("The wall shattered!");
|
||||||
HP_BAR(playerLeft);
|
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); }
|
TURN { MOVE(player, MOVE_CURSE); }
|
||||||
} SCENE {
|
} SCENE {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CURSE, player);
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_CURSE, player);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||||
MESSAGE("Wobbuffet's Speed fell!");
|
MESSAGE("Wobbuffet's Speed fell!");
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||||
MESSAGE("Wobbuffet's Attack rose!");
|
MESSAGE("Wobbuffet's Attack rose!");
|
||||||
MESSAGE("Wobbuffet's Defense 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 {
|
GIVEN {
|
||||||
PLAYER(SPECIES_WOBBUFFET);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
PLAYER(SPECIES_WYNAUT);
|
PLAYER(SPECIES_WYNAUT);
|
||||||
@ -226,7 +229,7 @@ DOUBLE_BATTLE_TEST("Instructed move will be absorbed by Lightning Rod if it turn
|
|||||||
OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN {
|
TURN {
|
||||||
MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft);
|
MOVE(playerLeft, MOVE_TACKLE, target: moveTarget);
|
||||||
MOVE(opponentLeft, MOVE_PLASMA_FISTS, target: playerLeft);
|
MOVE(opponentLeft, MOVE_PLASMA_FISTS, target: playerLeft);
|
||||||
MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft);
|
MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft);
|
||||||
MOVE(opponentRight, MOVE_CELEBRATE);
|
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);
|
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_REFLECT; }
|
||||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||||
|
|
||||||
KNOWN_FAILING;
|
|
||||||
GIVEN {
|
GIVEN {
|
||||||
PLAYER(SPECIES_WOBBUFFET);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
OPPONENT(SPECIES_GASTLY);
|
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")
|
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);
|
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
|
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