Merge branch 'master' of https://github.com/rh-hideout/pokeemerald-expansion into rh-hideout-master
This commit is contained in:
commit
e94050f53c
@ -615,6 +615,24 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "SabataLunar",
|
||||
"name": "SabataLunar",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/26584469?v=4",
|
||||
"profile": "https://github.com/SabataLunar",
|
||||
"contributions": [
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "PacFire",
|
||||
"name": "PacFire",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/108960850?v=4",
|
||||
"profile": "https://github.com/PacFire",
|
||||
"contributions": [
|
||||
"design"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
@ -88,6 +88,10 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://hufford.io"><img src="https://avatars.githubusercontent.com/u/8021794?v=4?s=100" width="100px;" alt="Josh Hufford"/><br /><sub><b>Josh Hufford</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=ostomachion" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Kasenn"><img src="https://avatars.githubusercontent.com/u/115586266?v=4?s=100" width="100px;" alt="Kasenn"/><br /><sub><b>Kasenn</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=Kasenn" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SabataLunar"><img src="https://avatars.githubusercontent.com/u/26584469?v=4?s=100" width="100px;" alt="SabataLunar"/><br /><sub><b>SabataLunar</b></sub></a><br /><a href="#design-SabataLunar" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PacFire"><img src="https://avatars.githubusercontent.com/u/108960850?v=4?s=100" width="100px;" alt="PacFire"/><br /><sub><b>PacFire</b></sub></a><br /><a href="#design-PacFire" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
|
||||
@ -1171,24 +1171,59 @@ BattleScript_EffectSpectralThiefFromDamage:
|
||||
BattleScript_EffectPartingShot::
|
||||
attackcanceler
|
||||
jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_ATK, MIN_STAT_STAGE, BattleScript_EffectPartingShotTryAtk
|
||||
jumpifstat BS_TARGET, CMP_EQUAL, STAT_SPATK, MIN_STAT_STAGE, BattleScript_CantLowerMultipleStats
|
||||
jumpifstat BS_TARGET, CMP_EQUAL, STAT_SPATK, MIN_STAT_STAGE, BattleScript_EffectPartingShotCantLowerMultipleStats
|
||||
BattleScript_EffectPartingShotTryAtk:
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
attackanimation
|
||||
waitanimation
|
||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
||||
setstatchanger STAT_ATK, 1, TRUE
|
||||
statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectPartingShotTrySpAtk, BIT_SPATK
|
||||
printfromtable gStatDownStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
call BattleScript_EffectPartingShotMaybePrintStat
|
||||
BattleScript_EffectPartingShotTrySpAtk:
|
||||
setstatchanger STAT_SPATK, 1, TRUE
|
||||
statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectPartingShotSwitch
|
||||
printfromtable gStatDownStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectPartingShotMaybeSwitch
|
||||
call BattleScript_EffectPartingShotMaybePrintStat
|
||||
BattleScript_EffectPartingShotMaybeSwitch:
|
||||
jumpifgenconfiglowerthan CONFIG_PARTING_SHOT_SWITCH, GEN_7, BattleScript_EffectPartingShotSwitch
|
||||
jumpifbyte CMP_NOT_EQUAL, sB_ANIM_TARGETS_HIT, 0, BattleScript_EffectPartingShotSwitch
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectPartingShotSwitch:
|
||||
moveendall
|
||||
goto BattleScript_MoveSwitchPursuitEnd
|
||||
|
||||
BattleScript_EffectPartingShotCantLowerMultipleStats:
|
||||
pause B_WAIT_TIME_SHORT
|
||||
setmoveresultflags MOVE_RESULT_FAILED
|
||||
call BattleScript_EffectPartingShotPrintWontDecrease
|
||||
setbyte sB_ANIM_TARGETS_HIT, 0
|
||||
goto BattleScript_EffectPartingShotMaybeSwitch
|
||||
|
||||
BattleScript_EffectPartingShotMaybePrintStat:
|
||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_ATTACKER_STAT_CHANGED, BattleScript_EffectPartingShotPrintStat
|
||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_CHANGED, BattleScript_EffectPartingShotPrintStat
|
||||
return
|
||||
|
||||
BattleScript_EffectPartingShotPrintStat:
|
||||
setbyte sB_ANIM_TARGETS_HIT, 1
|
||||
printfromtable gStatDownStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_EffectPartingShotPrintWontDecrease:
|
||||
jumpifability BS_TARGET, ABILITY_CONTRARY, BattleScript_EffectPartingShotPrintWontDecreaseContrary
|
||||
printstring STRINGID_STATSWONTDECREASE2
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_EffectPartingShotPrintWontDecreaseContrary:
|
||||
swapattackerwithtarget
|
||||
printstring STRINGID_STATSWONTDECREASE2
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
swapattackerwithtarget
|
||||
return
|
||||
|
||||
BattleScript_EffectPowder::
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_MoveMissedPause, NO_ACC_CALC_CHECK_LOCK_ON
|
||||
@ -1224,6 +1259,7 @@ BattleScript_EffectAromaticMistWontGoHigher:
|
||||
|
||||
BattleScript_EffectMagneticFlux::
|
||||
attackcanceler
|
||||
savetarget
|
||||
setbyte gBattleCommunication, 0
|
||||
BattleScript_EffectMagneticFluxStart:
|
||||
jumpifability BS_TARGET, ABILITY_MINUS, BattleScript_EffectMagneticFluxCheckStats
|
||||
@ -1252,13 +1288,16 @@ BattleScript_EffectMagneticFluxTrySpDef:
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_EffectMagneticFluxLoop:
|
||||
jumpifbytenotequal gBattlerTarget, gBattlerAttacker, BattleScript_EffectMagneticFluxEnd
|
||||
jumpifnoally BS_ATTACKER, BattleScript_EffectMagneticFluxEnd
|
||||
setallytonexttarget BattleScript_EffectMagneticFluxStart
|
||||
BattleScript_EffectMagneticFluxEnd:
|
||||
restoretarget
|
||||
jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0, BattleScript_MoveEnd
|
||||
goto BattleScript_ButItFailed
|
||||
|
||||
BattleScript_EffectGearUp::
|
||||
attackcanceler
|
||||
savetarget
|
||||
setbyte gBattleCommunication, 0
|
||||
BattleScript_EffectGearUpStart:
|
||||
jumpifability BS_TARGET, ABILITY_MINUS, BattleScript_EffectGearUpCheckStats
|
||||
@ -1287,8 +1326,10 @@ BattleScript_EffectGearUpTrySpAtk:
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_EffectGearUpLoop:
|
||||
jumpifbytenotequal gBattlerTarget, gBattlerAttacker, BattleScript_EffectGearUpEnd
|
||||
jumpifnoally BS_ATTACKER, BattleScript_EffectGearUpEnd
|
||||
setallytonexttarget BattleScript_EffectGearUpStart
|
||||
BattleScript_EffectGearUpEnd:
|
||||
restoretarget
|
||||
jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0, BattleScript_MoveEnd
|
||||
goto BattleScript_ButItFailed
|
||||
|
||||
@ -2316,6 +2357,9 @@ BattleScript_TryTailwindAbilitiesLoop_WindPower:
|
||||
BattleScript_EffectMiracleEye::
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
jumpifgenconfiglowerthan CONFIG_MIRACLE_EYE_FAIL, GEN_5, BattleScript_MiracleEyeSet
|
||||
jumpifvolatile BS_TARGET, VOLATILE_MIRACLE_EYE, BattleScript_ButItFailed
|
||||
BattleScript_MiracleEyeSet:
|
||||
setvolatile BS_TARGET, VOLATILE_MIRACLE_EYE
|
||||
goto BattleScript_IdentifiedFoe
|
||||
|
||||
@ -3438,7 +3482,11 @@ BattleScript_EffectSpikes::
|
||||
BattleScript_EffectForesight::
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
|
||||
jumpifgenconfiglowerthan CONFIG_FORESIGHT_FAIL, GEN_3, BattleScript_ForesightFailCheck
|
||||
jumpifgenconfiglowerthan CONFIG_FORESIGHT_FAIL, GEN_5, BattleScript_ForesightSet
|
||||
BattleScript_ForesightFailCheck:
|
||||
jumpifvolatile BS_TARGET, VOLATILE_FORESIGHT, BattleScript_ButItFailed
|
||||
BattleScript_ForesightSet:
|
||||
setvolatile BS_TARGET, VOLATILE_FORESIGHT
|
||||
BattleScript_IdentifiedFoe:
|
||||
attackanimation
|
||||
|
||||
@ -34,9 +34,9 @@ will NOT be merged until after the next Minor Release.
|
||||
---
|
||||
|
||||
## What is a "Big Feature"?
|
||||
* If the original owner of the PR thinks a feature should be labeled a Big Feature, it is, no questions asked
|
||||
* If a reviewer thinks a PR is a Big Feature, then it is
|
||||
* If the two disagree, it can be discussed in a PR thread, and can ultimately be resolved with a Maintainer vote.
|
||||
* If any maintainer thinks a PR is a Big Feature, then it is, no question asked
|
||||
* If there is disagreement, it can be discussed in a PR thread, and can ultimately be resolved with a Maintainer vote.
|
||||
* If you believe your PR should have this feature, please let a maintainer know.
|
||||
|
||||
### How To Identify a Big Feature
|
||||
* **Big diffs**: It's easy for something to go unnoticed in review when it's a tiny part of a massive diff.
|
||||
|
||||
@ -27,26 +27,6 @@
|
||||
#include "random.h" // for rng_value_t
|
||||
#include "trainer_slide.h"
|
||||
|
||||
// Helper for accessing command arguments and advancing gBattlescriptCurrInstr.
|
||||
//
|
||||
// For example accuracycheck is defined as:
|
||||
//
|
||||
// .macro accuracycheck failInstr:req, move:req
|
||||
// .byte 0x1
|
||||
// .4byte \failInstr
|
||||
// .2byte \move
|
||||
// .endm
|
||||
//
|
||||
// Which corresponds to:
|
||||
//
|
||||
// CMD_ARGS(const u8 *failInstr, u16 move);
|
||||
//
|
||||
// The arguments can be accessed as cmd->failInstr and cmd->move.
|
||||
// gBattlescriptCurrInstr = cmd->nextInstr; advances to the next instruction.
|
||||
#define CMD_ARGS(...) const struct __attribute__((packed)) { u8 opcode; RECURSIVELY(R_FOR_EACH(APPEND_SEMICOLON, __VA_ARGS__)) const u8 nextInstr[0]; } *const cmd UNUSED = (const void *)gBattlescriptCurrInstr
|
||||
#define VARIOUS_ARGS(...) CMD_ARGS(u8 battler, u8 id, ##__VA_ARGS__)
|
||||
#define NATIVE_ARGS(...) CMD_ARGS(void (*func)(void), ##__VA_ARGS__)
|
||||
|
||||
// Used to exclude moves learned temporarily by Transform or Mimic
|
||||
#define MOVE_IS_PERMANENT(battler, moveSlot) \
|
||||
(!(gBattleMons[battler].volatiles.transformed) \
|
||||
@ -1230,7 +1210,7 @@ static inline struct PartyState *GetBattlerPartyState(u32 battler)
|
||||
|
||||
static inline bool32 IsDoubleBattle(void)
|
||||
{
|
||||
return (gBattleTypeFlags & BATTLE_TYPE_MORE_THAN_TWO_BATTLERS);
|
||||
return !!(gBattleTypeFlags & BATTLE_TYPE_MORE_THAN_TWO_BATTLERS);
|
||||
}
|
||||
|
||||
static inline bool32 IsSpreadMove(u32 moveTarget)
|
||||
|
||||
@ -96,6 +96,7 @@
|
||||
#define B_CAN_SPITE_FAIL GEN_LATEST // In Gen4+, Spite can no longer fail if the foe's last move only has 1 remaining PP.
|
||||
#define B_CRASH_IF_TARGET_IMMUNE GEN_LATEST // In Gen4+, moves with crash damage will crash if the user attacks a target that is immune due to their typing.
|
||||
#define B_MEMENTO_FAIL GEN_LATEST // In Gen4+, Memento no longer fails if the target already has -6 Attack and Special Attack. Additionally, in Gen5+, it fails if there is no target, or if the target is protected or behind a Substitute.
|
||||
#define B_PARTING_SHOT_SWITCH GEN_LATEST // In Gen7+, the user won't switch out if Parting Shot fails to lower the target's stats.
|
||||
#define B_GLARE_GHOST GEN_LATEST // In Gen4+, Glare can hit Ghost-type Pokémon normally.
|
||||
#define B_SKILL_SWAP GEN_LATEST // In Gen4+, Skill Swap triggers switch-in abilities after use.
|
||||
#define B_BRICK_BREAK GEN_LATEST // In Gen4+, you can destroy your own side's screens. In Gen 5+, screens are not removed if the target is immune.
|
||||
@ -127,6 +128,8 @@
|
||||
#define B_AFTER_YOU_TURN_ORDER GEN_LATEST // In Gen8+, After You doesn't fail if the turn order wouldn't change after use.
|
||||
#define B_QUASH_TURN_ORDER GEN_LATEST // In Gen8+, Quash-affected battlers move according to speed order. Before Gen8, Quash-affected battlers move in the order they were affected by Quash.
|
||||
#define B_DESTINY_BOND_FAIL GEN_LATEST // In Gen7+, Destiny Bond fails if used repeatedly.
|
||||
#define B_FORESIGHT_FAIL GEN_LATEST // In Gen2 and Gen5+, Foresight fails if used against a target already under its effect.
|
||||
#define B_MIRACLE_EYE_FAIL GEN_LATEST // In Gen5+, Miracle Eye fails if used against a target already under its effect.
|
||||
#define B_PURSUIT_TARGET GEN_LATEST // In Gen4+, Pursuit attacks a switching opponent even if they weren't targeting them. Before Gen4, Pursuit only attacks a switching opponent that it originally targeted.
|
||||
#define B_SKIP_RECHARGE GEN_LATEST // In Gen1, recharging moves such as Hyper Beam skip the recharge if the target gets KO'd
|
||||
#define B_ENCORE_TARGET GEN_LATEST // In Gen5+, encored moves are allowed to choose a target
|
||||
|
||||
@ -89,6 +89,7 @@
|
||||
F(CAN_SPITE_FAIL, canSpiteFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(CRASH_IF_TARGET_IMMUNE, crashIfTargetImmune, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(MEMENTO_FAIL, mementoFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(PARTING_SHOT_SWITCH, partingShotSwitch, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(GLARE_GHOST, glareGhost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(SKILL_SWAP, skillSwap, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(BRICK_BREAK, brickBreak, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
@ -118,6 +119,8 @@
|
||||
F(AFTER_YOU_TURN_ORDER, afterYouTurnOrder, (u32, GEN_COUNT - 1)) \
|
||||
F(QUASH_TURN_ORDER, quashTurnOrder, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(DESTINY_BOND_FAIL, destinyBondFail, (u32, GEN_COUNT - 1)) \
|
||||
F(FORESIGHT_FAIL, foresightFail, (u32, GEN_COUNT - 1)) \
|
||||
F(MIRACLE_EYE_FAIL, miracleEyeFail, (u32, GEN_COUNT - 1)) \
|
||||
F(PURSUIT_TARGET, pursuitTarget, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(SKIP_RECHARGE, skipRecharge, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(ENCORE_TARGET, encoreTarget, (u32, GEN_COUNT - 1)) \
|
||||
|
||||
@ -63,4 +63,11 @@ enum {
|
||||
bool32 CanThrowBall(void);
|
||||
bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon);
|
||||
|
||||
enum ItemTMHMOrEvolutionStone
|
||||
{
|
||||
ITEM_IS_OTHER,
|
||||
ITEM_IS_TM_HM,
|
||||
ITEM_IS_EVOLUTION_STONE,
|
||||
};
|
||||
|
||||
#endif // GUARD_ITEM_USE_H
|
||||
|
||||
@ -5500,9 +5500,9 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
|
||||
tailwindScore += 1;
|
||||
if (speed <= foe2Speed && (speed * 2) > foe2Speed)
|
||||
tailwindScore += 1;
|
||||
if (partnerSpeed <= foe1Speed && (speed * 2) > foe1Speed)
|
||||
if (partnerSpeed <= foe1Speed && (partnerSpeed * 2) > foe1Speed)
|
||||
tailwindScore += 1;
|
||||
if (partnerSpeed <= foe1Speed && (speed * 2) > foe1Speed)
|
||||
if (partnerSpeed <= foe2Speed && (partnerSpeed * 2) > foe2Speed)
|
||||
tailwindScore += 1;
|
||||
|
||||
if (tailwindScore > 0)
|
||||
|
||||
@ -1960,40 +1960,45 @@ bool32 IsAllyProtectingFromMove(u32 battlerAtk, u32 attackerMove, u32 allyMove)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
enum ProtectMethod protectMethod = GetMoveProtectMethod(allyMove);
|
||||
|
||||
if (protectMethod == PROTECT_QUICK_GUARD)
|
||||
{
|
||||
u32 priority = GetBattleMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk], attackerMove);
|
||||
return (priority > 0);
|
||||
}
|
||||
|
||||
if (IsBattleMoveStatus(attackerMove))
|
||||
{
|
||||
switch (protectMethod)
|
||||
{
|
||||
case PROTECT_NORMAL:
|
||||
case PROTECT_CRAFTY_SHIELD:
|
||||
case PROTECT_MAX_GUARD:
|
||||
case PROTECT_WIDE_GUARD:
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
if (!IsBattleMoveStatus(attackerMove))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if (GetMoveEffect(attackerMove) == EFFECT_HOLD_HANDS)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (protectMethod)
|
||||
{
|
||||
case PROTECT_CRAFTY_SHIELD:
|
||||
return FALSE;
|
||||
default:
|
||||
u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, attackerMove);
|
||||
return (GetBattlerSide(battlerAtk) != GetBattlerSide(BATTLE_PARTNER(battlerAtk))
|
||||
&& moveTarget != MOVE_TARGET_OPPONENTS_FIELD
|
||||
&& moveTarget != MOVE_TARGET_ALL_BATTLERS);
|
||||
}
|
||||
case PROTECT_WIDE_GUARD:
|
||||
return IsSpreadMove(GetBattlerMoveTargetType(battlerAtk, attackerMove));
|
||||
case PROTECT_NORMAL:
|
||||
case PROTECT_SPIKY_SHIELD:
|
||||
case PROTECT_MAX_GUARD:
|
||||
case PROTECT_BANEFUL_BUNKER:
|
||||
case PROTECT_BURNING_BULWARK:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
case PROTECT_OBSTRUCT:
|
||||
case PROTECT_SILK_TRAP:
|
||||
case PROTECT_KINGS_SHIELD:
|
||||
return !IsBattleMoveStatus(attackerMove);
|
||||
case PROTECT_QUICK_GUARD:
|
||||
return (GetChosenMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk]) > 0);
|
||||
case PROTECT_MAT_BLOCK:
|
||||
return !IsBattleMoveStatus(attackerMove);
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -457,43 +457,3 @@ void ChooseDamageNonTypesString(enum Type type)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Updates Dynamax HP multipliers and healthboxes.
|
||||
void BS_UpdateDynamax(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
u32 battler = gBattleScripting.battler;
|
||||
struct Pokemon *mon = GetBattlerMon(battler);
|
||||
|
||||
if (!IsGigantamaxed(battler)) // RecalcBattlerStats will get called on form change.
|
||||
RecalcBattlerStats(battler, mon, GetActiveGimmick(battler) == GIMMICK_DYNAMAX);
|
||||
|
||||
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
// Goes to the jump instruction if the target is Dynamaxed.
|
||||
void BS_JumpIfDynamaxed(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *jumpInstr);
|
||||
if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX))
|
||||
gBattlescriptCurrInstr = cmd->jumpInstr;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_UndoDynamax(void)
|
||||
{
|
||||
NATIVE_ARGS(u8 battler);
|
||||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
|
||||
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX)
|
||||
{
|
||||
UndoDynamax(battler);
|
||||
gBattleScripting.battler = battler;
|
||||
BattleScriptCall(BattleScript_DynamaxEnds_Ret);
|
||||
return;
|
||||
}
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
@ -72,6 +72,26 @@
|
||||
#include "load_save.h"
|
||||
#include "test/test_runner_battle.h"
|
||||
|
||||
// Helper for accessing command arguments and advancing gBattlescriptCurrInstr.
|
||||
//
|
||||
// For example accuracycheck is defined as:
|
||||
//
|
||||
// .macro accuracycheck failInstr:req, move:req
|
||||
// .byte 0x1
|
||||
// .4byte \failInstr
|
||||
// .2byte \move
|
||||
// .endm
|
||||
//
|
||||
// Which corresponds to:
|
||||
//
|
||||
// CMD_ARGS(const u8 *failInstr, u16 move);
|
||||
//
|
||||
// The arguments can be accessed as cmd->failInstr and cmd->move.
|
||||
// gBattlescriptCurrInstr = cmd->nextInstr; advances to the next instruction.
|
||||
#define CMD_ARGS(...) const struct __attribute__((packed)) { u8 opcode; RECURSIVELY(R_FOR_EACH(APPEND_SEMICOLON, __VA_ARGS__)) const u8 nextInstr[0]; } *const cmd UNUSED = (const void *)gBattlescriptCurrInstr
|
||||
#define VARIOUS_ARGS(...) CMD_ARGS(u8 battler, u8 id, ##__VA_ARGS__)
|
||||
#define NATIVE_ARGS(...) CMD_ARGS(void (*func)(void), ##__VA_ARGS__)
|
||||
|
||||
// table to avoid ugly powing on gba (courtesy of doesnt)
|
||||
// this returns (i^2.5)/4
|
||||
// the quarters cancel so no need to re-quadruple them in actual calculation
|
||||
@ -3451,7 +3471,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
|
||||
if (i)
|
||||
{
|
||||
BattleScriptPush(battleScript);
|
||||
if (gCurrentMove == MOVE_HYPERSPACE_FURY)
|
||||
if (GetMoveEffect(gCurrentMove) == EFFECT_HYPERSPACE_FURY)
|
||||
gBattlescriptCurrInstr = BattleScript_HyperspaceFuryRemoveProtect;
|
||||
else
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEffectFeint;
|
||||
@ -6153,7 +6173,7 @@ static void Cmd_moveend(void)
|
||||
// Not strictly a protect effect, but works the same way
|
||||
if (IsBattlerUsingBeakBlast(gBattlerTarget)
|
||||
&& CanBeBurned(gBattlerAttacker, gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
gBattleMons[gBattlerAttacker].status1 = STATUS1_BURN;
|
||||
@ -9733,7 +9753,8 @@ static void Cmd_setprotectlike(void)
|
||||
|
||||
if ((sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] >= RandomUniform(RNG_PROTECT_FAIL, 0, USHRT_MAX) && notLastTurn)
|
||||
|| (protectMethod == PROTECT_WIDE_GUARD && GetConfig(CONFIG_WIDE_GUARD) >= GEN_6)
|
||||
|| (protectMethod == PROTECT_QUICK_GUARD && GetConfig(CONFIG_QUICK_GUARD) >= GEN_6))
|
||||
|| (protectMethod == PROTECT_QUICK_GUARD && GetConfig(CONFIG_QUICK_GUARD) >= GEN_6)
|
||||
|| (protectMethod == PROTECT_CRAFTY_SHIELD))
|
||||
{
|
||||
if (GetMoveEffect(gCurrentMove) == EFFECT_ENDURE)
|
||||
{
|
||||
@ -10375,6 +10396,8 @@ static u32 ChangeStatBuffs(u32 battler, s8 statValue, enum Stat statId, union St
|
||||
}
|
||||
else if (battlerAbility == ABILITY_MIRROR_ARMOR && !flags.mirrorArmored && gBattlerAttacker != gBattlerTarget && battler == gBattlerTarget)
|
||||
{
|
||||
if (GetMoveEffect(gCurrentMove) == EFFECT_PARTING_SHOT)
|
||||
gBattleScripting.animTargetsHit = 1;
|
||||
if (flags.allowPtr)
|
||||
{
|
||||
SET_STATCHANGER(statId, GET_STAT_BUFF_VALUE(statValue) | STAT_BUFF_NEGATIVE, TRUE);
|
||||
@ -18081,3 +18104,43 @@ void BS_TryAbsorbToxicSpikesOnFaint(void)
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
// Updates Dynamax HP multipliers and healthboxes.
|
||||
void BS_UpdateDynamax(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
u32 battler = gBattleScripting.battler;
|
||||
struct Pokemon *mon = GetBattlerMon(battler);
|
||||
|
||||
if (!IsGigantamaxed(battler)) // RecalcBattlerStats will get called on form change.
|
||||
RecalcBattlerStats(battler, mon, GetActiveGimmick(battler) == GIMMICK_DYNAMAX);
|
||||
|
||||
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
// Goes to the jump instruction if the target is Dynamaxed.
|
||||
void BS_JumpIfDynamaxed(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *jumpInstr);
|
||||
if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX))
|
||||
gBattlescriptCurrInstr = cmd->jumpInstr;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_UndoDynamax(void)
|
||||
{
|
||||
NATIVE_ARGS(u8 battler);
|
||||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
|
||||
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX)
|
||||
{
|
||||
UndoDynamax(battler);
|
||||
gBattleScripting.battler = battler;
|
||||
BattleScriptCall(BattleScript_DynamaxEnds_Ret);
|
||||
return;
|
||||
}
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
@ -6635,6 +6635,26 @@ static inline bool32 IsSideProtected(u32 battler, enum ProtectMethod method)
|
||||
|| gProtectStructs[BATTLE_PARTNER(battler)].protected == method;
|
||||
}
|
||||
|
||||
static bool32 IsCraftyShieldProtected(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
if (!IsBattleMoveStatus(move))
|
||||
return FALSE;
|
||||
|
||||
if (!IsSideProtected(battlerDef, PROTECT_CRAFTY_SHIELD))
|
||||
return FALSE;
|
||||
|
||||
if (GetMoveEffect(move) == EFFECT_HOLD_HANDS)
|
||||
return TRUE;
|
||||
|
||||
u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move);
|
||||
if (!IsBattlerAlly(battlerAtk, battlerDef)
|
||||
&& moveTarget != MOVE_TARGET_OPPONENTS_FIELD
|
||||
&& moveTarget != MOVE_TARGET_ALL_BATTLERS)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
if (gProtectStructs[battlerDef].protected == PROTECT_NONE
|
||||
@ -6652,9 +6672,7 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
|
||||
bool32 isProtected = FALSE;
|
||||
|
||||
if (IsSideProtected(battlerDef, PROTECT_CRAFTY_SHIELD)
|
||||
&& IsBattleMoveStatus(move)
|
||||
&& GetMoveEffect(move) != EFFECT_COACHING)
|
||||
if (IsCraftyShieldProtected(battlerAtk, battlerDef, move))
|
||||
isProtected = TRUE;
|
||||
else if (MoveIgnoresProtect(move))
|
||||
isProtected = FALSE;
|
||||
|
||||
@ -8,15 +8,15 @@ const u16 gBattleEnvironmentPalette_Building[] = INCBIN_U16("graphics/battle_env
|
||||
|
||||
const u16 gBattleEnvironmentPalette_Kyogre[] = INCBIN_U16("graphics/battle_environment/water/kyogre.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_Groudon[] = INCBIN_U16("graphics/battle_environment/cave/groudon.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_BuildingGym[] = INCBIN_U16("graphics/battle_environment/building/palette2.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_BuildingLeader[] = INCBIN_U16("graphics/battle_environment/building/palette3.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumAqua[] = INCBIN_U16("graphics/battle_environment/stadium/palette1.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumMagma[] = INCBIN_U16("graphics/battle_environment/stadium/palette2.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumSidney[] = INCBIN_U16("graphics/battle_environment/stadium/palette3.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumPhoebe[] = INCBIN_U16("graphics/battle_environment/stadium/palette4.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumGlacia[] = INCBIN_U16("graphics/battle_environment/stadium/palette5.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumDrake[] = INCBIN_U16("graphics/battle_environment/stadium/palette6.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumWallace[] = INCBIN_U16("graphics/battle_environment/stadium/palette7.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_BuildingGym[] = INCBIN_U16("graphics/battle_environment/building/gym.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_BuildingLeader[] = INCBIN_U16("graphics/battle_environment/building/leader.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumAqua[] = INCBIN_U16("graphics/battle_environment/stadium/aqua.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumMagma[] = INCBIN_U16("graphics/battle_environment/stadium/magma.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumSidney[] = INCBIN_U16("graphics/battle_environment/stadium/sidney.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumPhoebe[] = INCBIN_U16("graphics/battle_environment/stadium/phoebe.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumGlacia[] = INCBIN_U16("graphics/battle_environment/stadium/glacia.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumDrake[] = INCBIN_U16("graphics/battle_environment/stadium/drake.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_StadiumWallace[] = INCBIN_U16("graphics/battle_environment/stadium/wallace.gbapal");
|
||||
const u16 gBattleEnvironmentPalette_Rayquaza[] = INCBIN_U16("graphics/battle_environment/sky/palette.gbapal");
|
||||
|
||||
const u32 gBattleEnvironmentAnimTiles_TallGrass[] = INCBIN_U32("graphics/battle_environment/tall_grass/anim_tiles.4bpp.smol");
|
||||
|
||||
@ -21,7 +21,7 @@ const u16 gItemIconPalette_UltraBall[] = INCBIN_U16("graphics/items/icon_palette
|
||||
const u32 gItemIcon_MasterBall[] = INCBIN_U32("graphics/items/icons/master_ball.4bpp.smol");
|
||||
const u16 gItemIconPalette_MasterBall[] = INCBIN_U16("graphics/items/icon_palettes/master_ball.gbapal");
|
||||
|
||||
const u32 gItemIcon_PremierBall[] = INCBIN_U16("graphics/items/icons/premier_ball.4bpp.smol");
|
||||
const u32 gItemIcon_PremierBall[] = INCBIN_U32("graphics/items/icons/premier_ball.4bpp.smol");
|
||||
const u16 gItemIconPalette_PremierBall[] = INCBIN_U16("graphics/items/icon_palettes/premier_ball.gbapal");
|
||||
|
||||
const u32 gItemIcon_HealBall[] = INCBIN_U32("graphics/items/icons/heal_ball.4bpp.smol");
|
||||
|
||||
@ -19386,7 +19386,7 @@ const u32 gObjectEventPic_Substitute[] = INCBIN_COMP("graphics/pokemon/question_
|
||||
const u16 gMonPalette_VivillonIcySnow[] = INCBIN_U16("graphics/pokemon/vivillon/normal.gbapal");
|
||||
const u32 gMonBackPic_VivillonIcySnow[] = INCBIN_U32("graphics/pokemon/vivillon/back.4bpp.smol");
|
||||
const u16 gMonShinyPalette_VivillonIcySnow[] = INCBIN_U16("graphics/pokemon/vivillon/shiny.gbapal");
|
||||
const u8 gMonIcon_VivillonIcySnow[] = INCBIN_U8("graphics/pokemon/vivillon/meadow/icon.4bpp");
|
||||
const u8 gMonIcon_VivillonIcySnow[] = INCBIN_U8("graphics/pokemon/vivillon/icon.4bpp");
|
||||
#if P_FOOTPRINTS
|
||||
const u8 gMonFootprint_Vivillon[] = INCBIN_U8("graphics/pokemon/vivillon/footprint.1bpp");
|
||||
#endif //P_FOOTPRINTS
|
||||
|
||||
@ -15818,7 +15818,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
.metronomeBanned = TRUE,
|
||||
.sketchBanned = (B_SKETCH_BANS >= GEN_9),
|
||||
.additionalEffects = ADDITIONAL_EFFECTS({
|
||||
// Feint move effect handled in script as it goes before animation
|
||||
.moveEffect = MOVE_EFFECT_FEINT, // TODO: Is this supposed to happen before the attack animation?
|
||||
},
|
||||
{
|
||||
.moveEffect = MOVE_EFFECT_DEF_MINUS_1,
|
||||
.self = TRUE,
|
||||
}),
|
||||
|
||||
@ -277,7 +277,11 @@ static const u8 sRSAvatarGfxIds[GENDER_COUNT] =
|
||||
[FEMALE] = OBJ_EVENT_GFX_LINK_RS_MAY
|
||||
};
|
||||
|
||||
static const u8 sPlayerAvatarGfxToStateFlag[GENDER_COUNT][5][2] =
|
||||
static const struct __attribute__((packed))
|
||||
{
|
||||
u8 graphicsId;
|
||||
u8 playerFlag;
|
||||
} sPlayerAvatarGfxToStateFlag[GENDER_COUNT][5] =
|
||||
{
|
||||
[MALE] =
|
||||
{
|
||||
@ -1577,8 +1581,8 @@ static u8 GetPlayerAvatarStateTransitionByGraphicsId(u16 graphicsId, u8 gender)
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(sPlayerAvatarGfxToStateFlag[0]); i++)
|
||||
{
|
||||
if (sPlayerAvatarGfxToStateFlag[gender][i][0] == graphicsId)
|
||||
return sPlayerAvatarGfxToStateFlag[gender][i][1];
|
||||
if (sPlayerAvatarGfxToStateFlag[gender][i].graphicsId == graphicsId)
|
||||
return sPlayerAvatarGfxToStateFlag[gender][i].playerFlag;
|
||||
}
|
||||
return PLAYER_AVATAR_FLAG_ON_FOOT;
|
||||
}
|
||||
@ -1590,8 +1594,8 @@ u16 GetPlayerAvatarGraphicsIdByCurrentState(void)
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(sPlayerAvatarGfxToStateFlag[0]); i++)
|
||||
{
|
||||
if (sPlayerAvatarGfxToStateFlag[gPlayerAvatar.gender][i][1] & flags)
|
||||
return sPlayerAvatarGfxToStateFlag[gPlayerAvatar.gender][i][0];
|
||||
if (sPlayerAvatarGfxToStateFlag[gPlayerAvatar.gender][i].playerFlag & flags)
|
||||
return sPlayerAvatarGfxToStateFlag[gPlayerAvatar.gender][i].graphicsId;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2612,8 +2612,6 @@ void CreateFrontierBrainPokemon(void)
|
||||
friendship = 0;
|
||||
}
|
||||
SetMonData(&gEnemyParty[monPartyId], MON_DATA_FRIENDSHIP, &friendship);
|
||||
j = FALSE;
|
||||
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_IS_SHINY, &j);
|
||||
CalculateMonStats(&gEnemyParty[monPartyId]);
|
||||
monPartyId++;
|
||||
}
|
||||
|
||||
@ -222,11 +222,11 @@ static void Task_CloseCantUseKeyItemMessage(u8 taskId)
|
||||
u8 CheckIfItemIsTMHMOrEvolutionStone(u16 itemId)
|
||||
{
|
||||
if (GetItemFieldFunc(itemId) == ItemUseOutOfBattle_TMHM)
|
||||
return 1;
|
||||
return ITEM_IS_TM_HM;
|
||||
else if (GetItemFieldFunc(itemId) == ItemUseOutOfBattle_EvolutionStone)
|
||||
return 2;
|
||||
return ITEM_IS_EVOLUTION_STONE;
|
||||
else
|
||||
return 0;
|
||||
return ITEM_IS_OTHER;
|
||||
}
|
||||
|
||||
// Mail in the bag menu can't have a message but it can be checked (view the mail background, no message)
|
||||
|
||||
@ -2620,5 +2620,3 @@ static const struct SpritePalette sSpritePalettes[] =
|
||||
{gNamingScreenMenu_Pal[4], PALTAG_OK_BUTTON},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1152,10 +1152,10 @@ static bool8 DisplayPartyPokemonDataForMoveTutorOrEvolutionItem(u8 slot)
|
||||
{
|
||||
default:
|
||||
return FALSE;
|
||||
case 1: // TM/HM
|
||||
case ITEM_IS_TM_HM: // TM/HM
|
||||
DisplayPartyPokemonDataToTeachMove(slot, ItemIdToBattleMoveId(item));
|
||||
break;
|
||||
case 2: // Evolution stone
|
||||
case ITEM_IS_EVOLUTION_STONE: // Evolution stone
|
||||
if (!GetMonData(currentPokemon, MON_DATA_IS_EGG) && GetEvolutionTargetSpecies(currentPokemon, EVO_MODE_ITEM_CHECK, item, NULL, NULL, CHECK_EVO) != SPECIES_NONE)
|
||||
return FALSE;
|
||||
DisplayPartyPokemonDescriptionData(slot, PARTYBOX_DESC_NO_USE);
|
||||
|
||||
@ -566,4 +566,3 @@ static s32 GetTypeIconBounceMovement(s32 originalY, u32 position)
|
||||
struct Sprite *healthbox = &gSprites[gHealthboxSpriteIds[GetBattlerAtPosition(position)]];
|
||||
return originalY + healthbox->y2;
|
||||
}
|
||||
|
||||
|
||||
@ -780,27 +780,33 @@ AI_DOUBLE_BATTLE_TEST("AI does not use Helping Hand on Good as Gold ally")
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Tailwind")
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Tailwind based on speed matchups")
|
||||
{
|
||||
u32 speed1, speed2, speed3, speed4;
|
||||
bool32 expectTailwind;
|
||||
|
||||
PARAMETRIZE { speed1 = 20; speed2 = 20; speed3 = 20; speed4 = 20; }
|
||||
PARAMETRIZE { speed1 = 20; speed2 = 20; speed3 = 5; speed4 = 5; }
|
||||
PARAMETRIZE { speed1 = 20; speed2 = 20; speed3 = 15; speed4 = 15; }
|
||||
PARAMETRIZE { speed1 = 1; speed2 = 1; speed3 = 5; speed4 = 5; }
|
||||
PARAMETRIZE { speed1 = 1; speed2 = 20; speed3 = 15; speed4 = 15; }
|
||||
PARAMETRIZE { speed1 = 1; speed2 = 20; speed3 = 20; speed4 = 15; }
|
||||
// All four comparisons qualify -> tailwindScore = 5
|
||||
PARAMETRIZE { speed1 = 20; speed2 = 20; speed3 = 20; speed4 = 20; expectTailwind = TRUE; }
|
||||
// Only the attacker flips one foe matchup -> tailwindScore = 2
|
||||
PARAMETRIZE { speed1 = 20; speed2 = 40; speed3 = 20; speed4 = 50; expectTailwind = TRUE; }
|
||||
// Only the partner flips one foe matchup -> tailwindScore = 2
|
||||
PARAMETRIZE { speed1 = 10; speed2 = 29; speed3 = 50; speed4 = 15; expectTailwind = TRUE; }
|
||||
// Too slow: even after doubling, still slower than both foes -> tailwindScore = 0.
|
||||
PARAMETRIZE { speed1 = 40; speed2 = 40; speed3 = 10; speed4 = 10; expectTailwind = FALSE; }
|
||||
// Already faster: Tailwind doesn't improve matchups -> tailwindScore = 0.
|
||||
PARAMETRIZE { speed1 = 5; speed2 = 5; speed3 = 10; speed4 = 10; expectTailwind = FALSE; }
|
||||
// Boundary: speed*2 == foe speed does not count -> tailwindScore = 0.
|
||||
PARAMETRIZE { speed1 = 20; speed2 = 20; speed3 = 10; speed4 = 30; expectTailwind = FALSE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_AFTER_YOU) == EFFECT_AFTER_YOU);
|
||||
ASSUME(GetMoveEffect(MOVE_TRICK_ROOM) == EFFECT_TRICK_ROOM);
|
||||
ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_DOUBLE_BATTLE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(speed1); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(speed2); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(speed3); Moves(MOVE_TAILWIND, MOVE_HEADBUTT); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(speed4); Moves(MOVE_TAILWIND, MOVE_HEADBUTT); }
|
||||
} WHEN {
|
||||
if (speed3 > 10)
|
||||
if (expectTailwind)
|
||||
TURN { EXPECT_MOVE(opponentLeft, MOVE_TAILWIND); }
|
||||
else
|
||||
TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_TAILWIND); }
|
||||
@ -874,3 +880,29 @@ AI_DOUBLE_BATTLE_TEST("AI prefers to Fake Out the opponent vulnerable to flinchi
|
||||
TURN { EXPECT_MOVE(opponentLeft, MOVE_FAKE_OUT, target:playerRight); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Gear Up")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_KLINKLANG) { Ability(ABILITY_PLUS); Moves(MOVE_GEAR_UP, MOVE_WATER_GUN, MOVE_POUND); }
|
||||
OPPONENT(SPECIES_KLINKLANG) { Ability(ABILITY_PLUS); Moves(MOVE_GEAR_UP, MOVE_WATER_GUN, MOVE_POUND); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponentLeft, MOVE_GEAR_UP); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Magnetic Flux")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_KLINK) { Ability(ABILITY_PLUS); Moves(MOVE_MAGNETIC_FLUX, MOVE_POUND); }
|
||||
OPPONENT(SPECIES_KLINK) { Ability(ABILITY_PLUS); Moves(MOVE_MAGNETIC_FLUX, MOVE_POUND); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponentLeft, MOVE_MAGNETIC_FLUX); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +87,6 @@ SINGLE_BATTLE_TEST("Beak Blast burns only when contact moves are used")
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_BEAK_BLAST); }
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_BEAK_BLAST_SETUP, player);
|
||||
MESSAGE("Wobbuffet started heating up its beak!");
|
||||
@ -112,6 +111,35 @@ SINGLE_BATTLE_TEST("Beak Blast burns only when contact moves are used")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Beak Blast doesn't burn when charging a two turn move")
|
||||
{
|
||||
u32 move;
|
||||
PARAMETRIZE { move = MOVE_BOUNCE; }
|
||||
PARAMETRIZE { move = MOVE_DIG; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_BOUNCE));
|
||||
ASSUME(MoveMakesContact(MOVE_DIG));
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_BOUNCE)].twoTurnEffect);
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_DIG)].twoTurnEffect);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_BEAK_BLAST); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_BEAK_BLAST_SETUP, player);
|
||||
MESSAGE("Wobbuffet started heating up its beak!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
|
||||
NONE_OF {
|
||||
HP_BAR(player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, opponent);
|
||||
MESSAGE("The opposing Wobbuffet was burned!");
|
||||
STATUS_ICON(opponent, burn: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Beak Blast doesn't burn fire types")
|
||||
{
|
||||
GIVEN {
|
||||
|
||||
@ -1,14 +1,123 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Foresight removes Ghost's type immunity to Normal and Fighting types")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_FORESIGHT) == EFFECT_FORESIGHT);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Foresight removes Ghost's type immunity to Normal and Fighting types")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveType(MOVE_SCRATCH) == TYPE_NORMAL);
|
||||
ASSUME(GetMoveType(MOVE_LOW_KICK) == TYPE_FIGHTING);
|
||||
ASSUME(GetSpeciesType(SPECIES_GENGAR, 0) == TYPE_GHOST);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_FORESIGHT, MOVE_SCRATCH, MOVE_LOW_KICK); }
|
||||
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_SPLASH); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FORESIGHT); MOVE(opponent, MOVE_SPLASH); }
|
||||
TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_SPLASH); }
|
||||
TURN { MOVE(player, MOVE_LOW_KICK); MOVE(opponent, MOVE_SPLASH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
|
||||
HP_BAR(opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LOW_KICK, player);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Foresight always hits unless the target is semi-invulnerable")
|
||||
{
|
||||
bool32 semiInvulnerable = FALSE;
|
||||
PARAMETRIZE { semiInvulnerable = FALSE; }
|
||||
PARAMETRIZE { semiInvulnerable = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP);
|
||||
ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_FORESIGHT, MOVE_SPLASH); Speed(10); }
|
||||
OPPONENT(SPECIES_SQUAWKABILLY) { Moves(MOVE_DOUBLE_TEAM, MOVE_FLY); Speed(20); }
|
||||
} WHEN {
|
||||
if (semiInvulnerable)
|
||||
TURN { MOVE(player, MOVE_FORESIGHT); MOVE(opponent, MOVE_FLY); }
|
||||
else
|
||||
TURN { MOVE(player, MOVE_FORESIGHT); MOVE(opponent, MOVE_DOUBLE_TEAM); }
|
||||
|
||||
if (semiInvulnerable)
|
||||
TURN { MOVE(player, MOVE_SPLASH); SKIP_TURN(opponent); }
|
||||
} SCENE {
|
||||
if (semiInvulnerable) {
|
||||
MESSAGE("The opposing Squawkabilly avoided the attack!");
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_TEAM, opponent);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Foresight causes moves against the target to ignore positive evasion stat stages")
|
||||
{
|
||||
PASSES_RANDOMLY(100, 100, RNG_ACCURACY);
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_FORESIGHT, MOVE_SCRATCH); Speed(10); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_DOUBLE_TEAM, MOVE_SPLASH); Speed(20); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FORESIGHT); MOVE(opponent, MOVE_DOUBLE_TEAM); }
|
||||
TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_SPLASH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_TEAM, opponent);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Foresight fails if the target is already under its effect (Gen 2 and Gen5+)")
|
||||
{
|
||||
u32 genConfig = GEN_2;
|
||||
PARAMETRIZE { genConfig = GEN_2; }
|
||||
PARAMETRIZE { genConfig = GEN_5; }
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_FORESIGHT_FAIL, genConfig);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FORESIGHT); }
|
||||
TURN { MOVE(player, MOVE_FORESIGHT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Foresight doesn't fail if the target is already under its effect (Gen 3-4)")
|
||||
{
|
||||
u32 genConfig = GEN_3;
|
||||
PARAMETRIZE { genConfig = GEN_3; }
|
||||
PARAMETRIZE { genConfig = GEN_4; }
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_FORESIGHT_FAIL, genConfig);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FORESIGHT); }
|
||||
TURN { MOVE(player, MOVE_FORESIGHT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
|
||||
NOT MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Foresight causes accuracy/evasion stat changes only between the user/target when the user's accuracy stage is less than the target's evasion stage (Gen 2)")
|
||||
TO_DO_BATTLE_TEST("Foresight causes all moves against the target to ignore evasion stat changes (Gen 3)")
|
||||
TO_DO_BATTLE_TEST("Foresight causes all moves against the target to ignore only positive evasion stat changes (Gen 4+)") // Eg. Doesn't ignore Sweet Scent
|
||||
TO_DO_BATTLE_TEST("Foresight doesn't cause moves used against the target to always hit (Gen 2-3)")
|
||||
TO_DO_BATTLE_TEST("Foresight causes moves used against the target to always hit (Gen 4+)")
|
||||
TO_DO_BATTLE_TEST("Foresight does not make moves hit semi-invulnerable targets")
|
||||
TO_DO_BATTLE_TEST("Foresight fails if the target is already under its effect (Gen 2 and Gen5+)")
|
||||
TO_DO_BATTLE_TEST("Foresight doesn't fail if the target is already under its effect (Gen 3-4)")
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Foresight's effect (Gen 2)");
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass Foresight's effect (Gen 3+)");
|
||||
|
||||
@ -1,17 +1,47 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Gear Up increases the Attack and Sp. Attack of the user and allies if they have Plus or Minus")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_GEAR_UP) == EFFECT_GEAR_UP);
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Gear Up")
|
||||
SINGLE_BATTLE_TEST("Gear Up raises Attack and Sp. Attack of the user with Plus/Minus in singles")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_KLINKLANG) { Ability(ABILITY_PLUS); Moves(MOVE_GEAR_UP, MOVE_WATER_GUN, MOVE_POUND); }
|
||||
OPPONENT(SPECIES_KLINKLANG) { Ability(ABILITY_PLUS); Moves(MOVE_GEAR_UP, MOVE_WATER_GUN, MOVE_POUND); }
|
||||
PLAYER(SPECIES_PLUSLE) { Ability(ABILITY_PLUS); }
|
||||
OPPONENT(SPECIES_MINUN) { Ability(ABILITY_MINUS); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponentLeft, MOVE_GEAR_UP); }
|
||||
TURN { MOVE(player, MOVE_GEAR_UP); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GEAR_UP, player);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Gear Up raises Attack and Sp. Attack of all Plus/Minus allies in doubles")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_PLUSLE) { Ability(ABILITY_PLUS); }
|
||||
PLAYER(SPECIES_MINUN) { Ability(ABILITY_MINUS); }
|
||||
OPPONENT(SPECIES_PLUSLE) { Ability(ABILITY_PLUS); }
|
||||
OPPONENT(SPECIES_MINUN) { Ability(ABILITY_MINUS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_GEAR_UP); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GEAR_UP, playerLeft);
|
||||
} THEN {
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(playerRight->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Hyperspace Fury (Move Effect) test titles")
|
||||
@ -1,17 +1,47 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Magnetic Flux (Move Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_MAGNETIC_FLUX) == EFFECT_MAGNETIC_FLUX);
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI uses Magnetic Flux")
|
||||
SINGLE_BATTLE_TEST("Magnetic Flux raises Defense and Sp. Defense of the user with Plus/Minus in singles")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_KLINK) { Ability(ABILITY_PLUS); Moves(MOVE_MAGNETIC_FLUX, MOVE_POUND); }
|
||||
OPPONENT(SPECIES_KLINK) { Ability(ABILITY_PLUS); Moves(MOVE_MAGNETIC_FLUX, MOVE_POUND); }
|
||||
PLAYER(SPECIES_PLUSLE) { Ability(ABILITY_PLUS); }
|
||||
OPPONENT(SPECIES_MINUN) { Ability(ABILITY_MINUS); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponentLeft, MOVE_MAGNETIC_FLUX); }
|
||||
TURN { MOVE(player, MOVE_MAGNETIC_FLUX); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGNETIC_FLUX, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Magnetic Flux raises Defense and Sp. Defense of all Plus/Minus allies in doubles")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_PLUSLE) { Ability(ABILITY_PLUS); }
|
||||
PLAYER(SPECIES_MINUN) { Ability(ABILITY_MINUS); }
|
||||
OPPONENT(SPECIES_PLUSLE) { Ability(ABILITY_PLUS); }
|
||||
OPPONENT(SPECIES_MINUN) { Ability(ABILITY_MINUS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_MAGNETIC_FLUX); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGNETIC_FLUX, playerLeft);
|
||||
} THEN {
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(playerRight->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(playerRight->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,106 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Miracle Eye (Move Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_MIRACLE_EYE) == EFFECT_MIRACLE_EYE);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Miracle Eye removes Dark-type immunity to Psychic-type moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveType(MOVE_PSYCHIC) == TYPE_PSYCHIC);
|
||||
ASSUME(GetSpeciesType(SPECIES_UMBREON, 0) == TYPE_DARK);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_MIRACLE_EYE, MOVE_PSYCHIC); }
|
||||
OPPONENT(SPECIES_UMBREON) { Moves(MOVE_SPLASH); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PSYCHIC); MOVE(opponent, MOVE_SPLASH); }
|
||||
TURN { MOVE(player, MOVE_MIRACLE_EYE); MOVE(opponent, MOVE_SPLASH); }
|
||||
TURN { MOVE(player, MOVE_PSYCHIC); MOVE(opponent, MOVE_SPLASH); }
|
||||
} SCENE {
|
||||
NOT HP_BAR(opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Miracle Eye always hits unless the target is semi-invulnerable")
|
||||
{
|
||||
bool32 semiInvulnerable = FALSE;
|
||||
PARAMETRIZE { semiInvulnerable = FALSE; }
|
||||
PARAMETRIZE { semiInvulnerable = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP);
|
||||
ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_MIRACLE_EYE, MOVE_SPLASH); Speed(10); }
|
||||
OPPONENT(SPECIES_SQUAWKABILLY) { Moves(MOVE_DOUBLE_TEAM, MOVE_FLY); Speed(20); }
|
||||
} WHEN {
|
||||
if (semiInvulnerable)
|
||||
TURN { MOVE(player, MOVE_MIRACLE_EYE); MOVE(opponent, MOVE_FLY); }
|
||||
else
|
||||
TURN { MOVE(player, MOVE_MIRACLE_EYE); MOVE(opponent, MOVE_DOUBLE_TEAM); }
|
||||
|
||||
if (semiInvulnerable)
|
||||
TURN { MOVE(player, MOVE_SPLASH); SKIP_TURN(opponent); }
|
||||
} SCENE {
|
||||
if (semiInvulnerable) {
|
||||
MESSAGE("Wobbuffet's attack missed!");
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_TEAM, opponent);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Miracle Eye causes moves against the target to ignore positive evasion stat stages")
|
||||
{
|
||||
PASSES_RANDOMLY(100, 100, RNG_ACCURACY);
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_MIRACLE_EYE, MOVE_SCRATCH); Speed(10); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_DOUBLE_TEAM, MOVE_SPLASH); Speed(20); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MIRACLE_EYE); MOVE(opponent, MOVE_DOUBLE_TEAM); }
|
||||
TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_SPLASH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_TEAM, opponent);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Miracle Eye fails if the target is already affected by Miracle Eye (Gen5+)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_MIRACLE_EYE_FAIL, GEN_5);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MIRACLE_EYE); }
|
||||
TURN { MOVE(player, MOVE_MIRACLE_EYE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Miracle Eye does not fail if the target is already affected by Miracle Eye (Gen4)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_MIRACLE_EYE_FAIL, GEN_4);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MIRACLE_EYE); }
|
||||
TURN { MOVE(player, MOVE_MIRACLE_EYE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
|
||||
NOT MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,385 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Parting Shot (Move Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_PARTING_SHOT) == EFFECT_PARTING_SHOT);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Passes Substitute and switches the user out")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SUBSTITUTE, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SUBSTITUTE); }
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); MOVE(opponent, MOVE_CELEBRATE); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, player);
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Soundproof and Good as Gold block Parting Shot")
|
||||
{
|
||||
u16 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_EXPLOUD; ability = ABILITY_SOUNDPROOF; }
|
||||
PARAMETRIZE { species = SPECIES_GHOLDENGO; ability = ABILITY_GOOD_AS_GOLD; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(IsSoundMove(MOVE_PARTING_SHOT));
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(species) { Ability(ability); Moves(MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ability);
|
||||
if (ability == ABILITY_SOUNDPROOF)
|
||||
MESSAGE("The opposing Exploud's Soundproof blocks Parting Shot!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WOBBUFFET);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Hyper Cutter blocks Attack drop but still switches")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, player);
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Magic Coat bounces it and switches the target out")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_MAGIC_COAT); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_MAGIC_COAT); MOVE(player, MOVE_PARTING_SHOT); SEND_OUT(opponent, 1); }
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(opponent->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Magic Bounce bounces it and switches the target out")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT); }
|
||||
OPPONENT(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); SEND_OUT(opponent, 1); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_MAGIC_BOUNCE);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(opponent->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Mirror Armor switches the user even if reflected drops fail")
|
||||
{
|
||||
u16 species, ability, item;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_METAGROSS; ability = ABILITY_CLEAR_BODY; item = ITEM_NONE; }
|
||||
PARAMETRIZE { species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; item = ITEM_NONE; }
|
||||
PARAMETRIZE { species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; item = ITEM_NONE; }
|
||||
PARAMETRIZE { species = SPECIES_LUCARIO; ability = ABILITY_INNER_FOCUS; item = ITEM_CLEAR_AMULET; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_CLEAR_AMULET].holdEffect == HOLD_EFFECT_CLEAR_AMULET);
|
||||
PLAYER(species) { Ability(ability); Item(item); Moves(MOVE_PARTING_SHOT); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_MIRROR_ARMOR);
|
||||
if (ability == ABILITY_CLEAR_BODY) {
|
||||
ABILITY_POPUP(player, ABILITY_CLEAR_BODY);
|
||||
MESSAGE("Metagross's Clear Body prevents stat loss!");
|
||||
} else if (ability == ABILITY_WHITE_SMOKE) {
|
||||
ABILITY_POPUP(player, ABILITY_WHITE_SMOKE);
|
||||
MESSAGE("Torkoal's White Smoke prevents stat loss!");
|
||||
} else if (ability == ABILITY_FULL_METAL_BODY) {
|
||||
ABILITY_POPUP(player, ABILITY_FULL_METAL_BODY);
|
||||
MESSAGE("Solgaleo's Full Metal Body prevents stat loss!");
|
||||
} else if (item == ITEM_CLEAR_AMULET) {
|
||||
MESSAGE("The effects of the Clear Amulet held by Lucario prevents its stats from being lowered!");
|
||||
}
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Mirror Armor switches even if reflected stats are at minimum")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT, MOVE_SHELL_SMASH, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); Moves(MOVE_TOPSY_TURVY, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SHELL_SMASH); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_SHELL_SMASH); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_SHELL_SMASH); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TOPSY_TURVY); }
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_MIRROR_ARMOR);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Does not switch if both stats are at minimum (Gen7+)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_7);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT, MOVE_TOPSY_TURVY, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_OMASTAR) { Moves(MOVE_SHELL_SMASH, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_TOPSY_TURVY); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
MESSAGE("The opposing Omastar's stats won't go any lower!");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], MIN_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], MIN_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WOBBUFFET);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Does not switch if Contrary is at maximum stats (Gen7+)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_7);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT, MOVE_TOPSY_TURVY, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_INKAY) { Ability(ABILITY_CONTRARY); Moves(MOVE_SHELL_SMASH, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_TOPSY_TURVY); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
MESSAGE("The opposing Inkay's stats won't go any higher!");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], MAX_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], MAX_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WOBBUFFET);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Stat drop prevention by abilities/items does not switch (Gen7+)")
|
||||
{
|
||||
u16 species, ability, item;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_METAGROSS; ability = ABILITY_CLEAR_BODY; item = ITEM_NONE; }
|
||||
PARAMETRIZE { species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; item = ITEM_NONE; }
|
||||
PARAMETRIZE { species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; item = ITEM_NONE; }
|
||||
PARAMETRIZE { species = SPECIES_LUCARIO; ability = ABILITY_INNER_FOCUS; item = ITEM_CLEAR_AMULET; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_7);
|
||||
ASSUME(gItemsInfo[ITEM_CLEAR_AMULET].holdEffect == HOLD_EFFECT_CLEAR_AMULET);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(species) { Ability(ability); Item(item); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WOBBUFFET);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Mist prevents stat drops and does not switch (Gen7+)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_7);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_MIST, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_MIST); MOVE(player, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_PARTING_SHOT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WOBBUFFET);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Parting Shot: Flower Veil prevents stat drops and does not switch (Gen7+)")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesType(SPECIES_BULBASAUR, 0) == TYPE_GRASS);
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_7);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_BULBASAUR);
|
||||
OPPONENT(SPECIES_COMFEY) { Ability(ABILITY_FLOWER_VEIL); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_PARTING_SHOT, target: opponentLeft); MOVE(playerRight, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, playerLeft);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(playerLeft->species, SPECIES_WOBBUFFET);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Switches if both stats are at minimum (Gen6)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_6);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT, MOVE_TOPSY_TURVY, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_OMASTAR) { Moves(MOVE_SHELL_SMASH, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_TOPSY_TURVY); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); MOVE(opponent, MOVE_CELEBRATE); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
MESSAGE("The opposing Omastar's stats won't go any lower!");
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], MIN_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], MIN_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Switches if Contrary is at maximum stats (Gen6)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_6);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT, MOVE_TOPSY_TURVY, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_INKAY) { Ability(ABILITY_CONTRARY); Moves(MOVE_SHELL_SMASH, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_TOPSY_TURVY); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); MOVE(opponent, MOVE_CELEBRATE); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
MESSAGE("The opposing Inkay's stats won't go any higher!");
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], MAX_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], MAX_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Stat drop prevention by abilities/items switches (Gen6)")
|
||||
{
|
||||
u16 species, ability, item;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_METAGROSS; ability = ABILITY_CLEAR_BODY; item = ITEM_NONE; }
|
||||
PARAMETRIZE { species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; item = ITEM_NONE; }
|
||||
PARAMETRIZE { species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; item = ITEM_NONE; }
|
||||
PARAMETRIZE { species = SPECIES_LUCARIO; ability = ABILITY_INNER_FOCUS; item = ITEM_CLEAR_AMULET; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_6);
|
||||
ASSUME(gItemsInfo[ITEM_CLEAR_AMULET].holdEffect == HOLD_EFFECT_CLEAR_AMULET);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(species) { Ability(ability); Item(item); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PARTING_SHOT); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, player);
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parting Shot: Mist prevents stat drops and switches (Gen6)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_6);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_MIST, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_MIST); MOVE(player, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_PARTING_SHOT); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, player);
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Parting Shot: Flower Veil prevents stat drops and switches (Gen6)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(CONFIG_PARTING_SHOT_SWITCH, GEN_6);
|
||||
ASSUME(GetSpeciesType(SPECIES_BULBASAUR, 0) == TYPE_GRASS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_PARTING_SHOT); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_PIKACHU);
|
||||
OPPONENT(SPECIES_BULBASAUR);
|
||||
OPPONENT(SPECIES_COMFEY) { Ability(ABILITY_FLOWER_VEIL); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_PARTING_SHOT, target: opponentLeft); MOVE(playerRight, MOVE_CELEBRATE); SEND_OUT(playerLeft, 2); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, playerLeft);
|
||||
SEND_IN_MESSAGE("Pikachu");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(playerLeft->species, SPECIES_PIKACHU);
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,6 +125,36 @@ SINGLE_BATTLE_TEST("Protect: King's Shield, Silk Trap and Obstruct protect from
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protect: King's Shield, Silk Trap and Obstruct don't lower stats when charging a two turn move")
|
||||
{
|
||||
u32 move, protectMove;
|
||||
PARAMETRIZE { move = MOVE_BOUNCE; protectMove = MOVE_KINGS_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_DIG; protectMove = MOVE_KINGS_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_BOUNCE; protectMove = MOVE_SILK_TRAP; }
|
||||
PARAMETRIZE { move = MOVE_DIG; protectMove = MOVE_SILK_TRAP; }
|
||||
PARAMETRIZE { move = MOVE_BOUNCE; protectMove = MOVE_OBSTRUCT; }
|
||||
PARAMETRIZE { move = MOVE_DIG; protectMove = MOVE_OBSTRUCT; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_BOUNCE));
|
||||
ASSUME(MoveMakesContact(MOVE_DIG));
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_BOUNCE)].twoTurnEffect);
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_DIG)].twoTurnEffect);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, protectMove); MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, protectMove, player);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
HP_BAR(player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protect: Spiky Shield does 1/8 dmg of max hp of attackers making contact and may faint them")
|
||||
{
|
||||
u16 usedMove = MOVE_NONE;
|
||||
@ -162,6 +192,32 @@ SINGLE_BATTLE_TEST("Protect: Spiky Shield does 1/8 dmg of max hp of attackers ma
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protect: Spiky Shield doesn't hurt attacker when charging a two turn move")
|
||||
{
|
||||
u32 move;
|
||||
PARAMETRIZE { move = MOVE_BOUNCE; }
|
||||
PARAMETRIZE { move = MOVE_DIG; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_BOUNCE));
|
||||
ASSUME(MoveMakesContact(MOVE_DIG));
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_BOUNCE)].twoTurnEffect);
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_DIG)].twoTurnEffect);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SPIKY_SHIELD); MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKY_SHIELD, player);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
HP_BAR(player);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protect: Baneful Bunker poisons Pokémon for moves making contact")
|
||||
{
|
||||
u16 usedMove = MOVE_NONE;
|
||||
@ -214,6 +270,32 @@ SINGLE_BATTLE_TEST("Protect: Baneful Bunker can't poison Pokémon if they are al
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protect: Baneful Bunker doesn't poison attacker when charging a two turn move")
|
||||
{
|
||||
u32 move;
|
||||
PARAMETRIZE { move = MOVE_BOUNCE; }
|
||||
PARAMETRIZE { move = MOVE_DIG; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_BOUNCE));
|
||||
ASSUME(MoveMakesContact(MOVE_DIG));
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_BOUNCE)].twoTurnEffect);
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_DIG)].twoTurnEffect);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_BANEFUL_BUNKER); MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BANEFUL_BUNKER, player);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
HP_BAR(player);
|
||||
STATUS_ICON(opponent, STATUS1_POISON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protect: Burning Bulwark burns Pokémon for moves making contact")
|
||||
{
|
||||
u16 usedMove = MOVE_NONE;
|
||||
@ -266,6 +348,32 @@ SINGLE_BATTLE_TEST("Protect: Burning Bulwark can't burn Pokémon if they are alr
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protect: Burning Bulwark doesn't burn attacker when charging a two turn move")
|
||||
{
|
||||
u32 move;
|
||||
PARAMETRIZE { move = MOVE_BOUNCE; }
|
||||
PARAMETRIZE { move = MOVE_DIG; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_BOUNCE));
|
||||
ASSUME(MoveMakesContact(MOVE_DIG));
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_BOUNCE)].twoTurnEffect);
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_DIG)].twoTurnEffect);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_BURNING_BULWARK); MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BURNING_BULWARK, player);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
HP_BAR(player);
|
||||
STATUS_ICON(opponent, STATUS1_BURN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protect: Recoil damage is not applied if target was protected")
|
||||
{
|
||||
u32 j, k;
|
||||
@ -528,7 +636,7 @@ DOUBLE_BATTLE_TEST("Protect: Quick Guard can not fail on consecutive turns (Gen6
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Protect: Crafty Shield protects self and ally from status moves")
|
||||
DOUBLE_BATTLE_TEST("Crafty Shield protects self and ally from opposing status moves")
|
||||
{
|
||||
u16 move = MOVE_NONE;
|
||||
struct BattlePokemon *targetOpponent = NULL;
|
||||
@ -569,6 +677,72 @@ DOUBLE_BATTLE_TEST("Protect: Crafty Shield protects self and ally from status mo
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Crafty Shield does not protect against status moves used on the user's side")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_AROMATHERAPY; }
|
||||
PARAMETRIZE { move = MOVE_ACUPRESSURE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_AROMATHERAPY) == EFFECT_HEAL_BELL);
|
||||
ASSUME(GetMoveEffect(MOVE_ACUPRESSURE) == EFFECT_ACUPRESSURE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(5); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(5); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(10); }
|
||||
OPPONENT(SPECIES_WYNAUT) { Speed(5); Status1(STATUS1_BURN); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(opponentLeft, MOVE_CRAFTY_SHIELD);
|
||||
if (move == MOVE_ACUPRESSURE)
|
||||
MOVE(opponentRight, move, target: opponentLeft);
|
||||
else
|
||||
MOVE(opponentRight, move);
|
||||
}
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CRAFTY_SHIELD, opponentLeft);
|
||||
if (move == MOVE_ACUPRESSURE) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AROMATHERAPY, opponentRight);
|
||||
STATUS_ICON(opponentRight, none: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Crafty Shield does not protect against entry hazard moves")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SPIKES; }
|
||||
PARAMETRIZE { move = MOVE_STEALTH_ROCK; }
|
||||
PARAMETRIZE { move = MOVE_TOXIC_SPIKES; }
|
||||
PARAMETRIZE { move = MOVE_STICKY_WEB; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); MOVE(playerLeft, move, target: opponentLeft); }
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CRAFTY_SHIELD, opponentLeft);
|
||||
if (move == MOVE_SPIKES) {
|
||||
MESSAGE("Spikes were scattered on the ground all around the opposing team!");
|
||||
} else if (move == MOVE_TOXIC_SPIKES) {
|
||||
MESSAGE("Poison spikes were scattered on the ground all around the opposing team!");
|
||||
} else if (move == MOVE_STEALTH_ROCK) {
|
||||
MESSAGE("Pointed stones float in the air around the opposing team!");
|
||||
} else {
|
||||
MESSAGE("A sticky web has been laid out on the ground around the opposing team!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protect: Protect does not block Confide or Decorate")
|
||||
{
|
||||
u32 move;
|
||||
@ -618,6 +792,11 @@ DOUBLE_BATTLE_TEST("Crafty Shield protects self and ally from Confide and Decora
|
||||
|
||||
DOUBLE_BATTLE_TEST("Crafty Shield does not protect against moves that target all battlers")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_FLOWER_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_PERISH_SONG; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesType(SPECIES_TANGELA, 0) == TYPE_GRASS);
|
||||
ASSUME(GetSpeciesType(SPECIES_TANGROWTH, 0) == TYPE_GRASS);
|
||||
@ -628,8 +807,9 @@ DOUBLE_BATTLE_TEST("Crafty Shield does not protect against moves that target all
|
||||
OPPONENT(SPECIES_SUNKERN);
|
||||
OPPONENT(SPECIES_SUNFLORA);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); MOVE(opponentRight, MOVE_CELEBRATE); MOVE(playerLeft, MOVE_FLOWER_SHIELD); MOVE(playerRight, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); MOVE(opponentRight, MOVE_CELEBRATE); MOVE(playerLeft, move); MOVE(playerRight, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
if (move == MOVE_FLOWER_SHIELD) {
|
||||
MESSAGE("Tangela used Flower Shield!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
@ -643,6 +823,13 @@ DOUBLE_BATTLE_TEST("Crafty Shield does not protect against moves that target all
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("The opposing Sunflora's Defense rose!");
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PERISH_SONG, playerLeft);
|
||||
NONE_OF {
|
||||
MESSAGE("The opposing Sunkern protected itself!");
|
||||
MESSAGE("The opposing Sunflora protected itself!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
97
test/battle/move_effects_combined/hyperspace_fury.c
Normal file
97
test/battle/move_effects_combined/hyperspace_fury.c
Normal file
@ -0,0 +1,97 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_HYPERSPACE_FURY) == EFFECT_HYPERSPACE_FURY);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_HYPERSPACE_FURY, MOVE_EFFECT_FEINT));
|
||||
ASSUME(MoveHasAdditionalEffectSelf(MOVE_HYPERSPACE_FURY, MOVE_EFFECT_DEF_MINUS_1));
|
||||
ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Hyperspace Fury fails if used by a Pokémon other than Hoopa Unbound")
|
||||
{
|
||||
u32 species;
|
||||
PARAMETRIZE { species = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE { species = SPECIES_HOOPA_CONFINED; }
|
||||
PARAMETRIZE { species = SPECIES_HOOPA_UNBOUND; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(species);
|
||||
OPPONENT(SPECIES_REGIROCK);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_HYPERSPACE_FURY); }
|
||||
} SCENE {
|
||||
switch (species)
|
||||
{
|
||||
case SPECIES_HOOPA_UNBOUND:
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPERSPACE_FURY, player);
|
||||
break;
|
||||
case SPECIES_HOOPA_CONFINED:
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPERSPACE_FURY, player);
|
||||
MESSAGE("But Hoopa can't use it the way it is now!");
|
||||
break;
|
||||
case SPECIES_WOBBUFFET:
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPERSPACE_FURY, player);
|
||||
MESSAGE("But Wobbuffet can't use the move!");
|
||||
break;
|
||||
default:
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPERSPACE_FURY, player);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Hyperspace Fury hits the target through Protect and breaks it")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_HOOPA_UNBOUND);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_REGIROCK);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_PROTECT); MOVE(playerLeft, MOVE_HYPERSPACE_FURY, target: opponentLeft); MOVE(playerRight, MOVE_SCRATCH, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPERSPACE_FURY, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerRight);
|
||||
HP_BAR(opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Hyperspace Fury lowers the user's Defense by 1 stage after hitting the target")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_HOOPA_UNBOUND);
|
||||
OPPONENT(SPECIES_REGIROCK);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_HYPERSPACE_FURY); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPERSPACE_FURY, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Hyperspace Fury breaks protection and lowers the user's Defense by 1 stage")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_HOOPA_UNBOUND);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_REGIROCK);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_PROTECT); MOVE(playerLeft, MOVE_HYPERSPACE_FURY, target: opponentLeft); MOVE(playerRight, MOVE_SCRATCH, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPERSPACE_FURY, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerRight);
|
||||
HP_BAR(opponentLeft);
|
||||
} THEN {
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user