mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 03:34:15 +01:00
Merge branch 'upcoming' into ultraburst
This commit is contained in:
commit
5e8caa8d45
@ -23,8 +23,9 @@ body:
|
||||
label: Version
|
||||
description: What version of pokeemerald-expansion are you using as a base?
|
||||
options:
|
||||
- 1.5.1 (Default)
|
||||
- 1.5.2 (Default)
|
||||
- upcoming (Edge)
|
||||
- 1.5.1
|
||||
- 1.5.0
|
||||
- 1.4.3
|
||||
- 1.4.2
|
||||
|
@ -23,8 +23,9 @@ body:
|
||||
label: Version
|
||||
description: What version of pokeemerald-expansion are you using as a base?
|
||||
options:
|
||||
- 1.5.1 (Default)
|
||||
- 1.5.2 (Default)
|
||||
- upcoming (Edge)
|
||||
- 1.5.1
|
||||
- 1.5.0
|
||||
- 1.4.3
|
||||
- 1.4.2
|
||||
|
3
.github/ISSUE_TEMPLATE/04_other_errors.yaml
vendored
3
.github/ISSUE_TEMPLATE/04_other_errors.yaml
vendored
@ -23,8 +23,9 @@ body:
|
||||
label: Version
|
||||
description: What version of pokeemerald-expansion are you using as a base?
|
||||
options:
|
||||
- 1.5.1 (Default)
|
||||
- 1.5.2 (Default)
|
||||
- upcoming (Edge)
|
||||
- 1.5.1
|
||||
- 1.5.0
|
||||
- 1.4.3
|
||||
- 1.4.2
|
||||
|
@ -1318,7 +1318,7 @@
|
||||
.2byte \holdEffect
|
||||
.4byte \jumpInstr
|
||||
.endm
|
||||
|
||||
|
||||
.macro dostockpilestatchangeswearoff, battler:req, statChangeInstr:req
|
||||
callnative BS_DoStockpileStatChangesWearOff
|
||||
.byte \battler
|
||||
@ -1354,7 +1354,7 @@
|
||||
.macro setsnow
|
||||
callnative BS_SetSnow
|
||||
.endm
|
||||
|
||||
|
||||
.macro setzeffect
|
||||
callnative BS_SetZEffect
|
||||
.endm
|
||||
@ -1364,12 +1364,6 @@
|
||||
callnative BS_TrySymbiosis
|
||||
.endm
|
||||
|
||||
@ returns TRUE or FALSE to gBattleCommunication[0]
|
||||
.macro canteleport battler:req
|
||||
callnative BS_CanTeleport
|
||||
.byte \battler
|
||||
.endm
|
||||
|
||||
@ returns B_SIDE_x to gBattleCommunication[0]
|
||||
.macro getbattlerside battler:req
|
||||
callnative BS_GetBattlerSide
|
||||
@ -2088,7 +2082,7 @@
|
||||
.macro swapsidestatuses
|
||||
various BS_ATTACKER, VARIOUS_SWAP_SIDE_STATUSES
|
||||
.endm
|
||||
|
||||
|
||||
.macro swapstats stat:req
|
||||
various BS_ATTACKER, VARIOUS_SWAP_STATS
|
||||
.byte \stat
|
||||
@ -2189,6 +2183,11 @@
|
||||
jumpifbyte CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_NO_EFFECT, \jumpInstr
|
||||
.endm
|
||||
|
||||
.macro jumpifside battler:req, side:req, equalJumpInstr:req
|
||||
getbattlerside \battler
|
||||
jumpifbyte CMP_EQUAL, gBattleCommunication, \side, \equalJumpInstr
|
||||
.endm
|
||||
|
||||
.macro jumpifbattletype flags:req, jumpInstr:req
|
||||
jumpifword CMP_COMMON_BITS, gBattleTypeFlags, \flags, \jumpInstr
|
||||
.endm
|
||||
|
@ -4023,6 +4023,8 @@ BattleScript_MoveMissedDoDamage::
|
||||
.if B_CRASH_IF_TARGET_IMMUNE < GEN_4
|
||||
jumpifhalfword CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_MoveEnd
|
||||
.endif
|
||||
moveendcase MOVEEND_PROTECT_LIKE_EFFECT @ Spiky Shield's damage happens before recoil.
|
||||
jumpifhasnohp BS_ATTACKER, BattleScript_MoveEnd
|
||||
printstring STRINGID_PKMNCRASHED
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
damagecalc
|
||||
@ -5300,15 +5302,14 @@ BattleScript_EffectHurricane:
|
||||
BattleScript_EffectTeleport:
|
||||
attackcanceler
|
||||
attackstring
|
||||
ppreduce
|
||||
.if B_TELEPORT_BEHAVIOR >= GEN_7
|
||||
canteleport BS_ATTACKER
|
||||
jumpifbyte CMP_EQUAL, gBattleCommunication, TRUE, BattleScript_EffectTeleportNew
|
||||
goto BattleScript_ButItFailed
|
||||
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_EffectBatonPass
|
||||
jumpifside BS_ATTACKER, B_SIDE_PLAYER, BattleScript_EffectBatonPass
|
||||
.else
|
||||
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_ButItFailed
|
||||
.endif
|
||||
BattleScript_EffectTeleportTryToRunAway:
|
||||
ppreduce
|
||||
getifcantrunfrombattle BS_ATTACKER
|
||||
jumpifbyte CMP_EQUAL, gBattleCommunication, BATTLE_RUN_FORBIDDEN, BattleScript_ButItFailed
|
||||
jumpifbyte CMP_EQUAL, gBattleCommunication, BATTLE_RUN_FAILURE, BattleScript_PrintAbilityMadeIneffective
|
||||
@ -5319,29 +5320,6 @@ BattleScript_EffectTeleportTryToRunAway:
|
||||
setoutcomeonteleport BS_ATTACKER
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectTeleportNew:
|
||||
getbattlerside BS_ATTACKER
|
||||
jumpifbyte CMP_EQUAL, gBattleCommunication, B_SIDE_OPPONENT, BattleScript_EffectTeleportTryToRunAway
|
||||
attackanimation
|
||||
waitanimation
|
||||
openpartyscreen BS_ATTACKER, BattleScript_EffectTeleportNewEnd
|
||||
switchoutabilities BS_ATTACKER
|
||||
waitstate
|
||||
switchhandleorder BS_ATTACKER, 2
|
||||
returntoball BS_ATTACKER
|
||||
getswitchedmondata BS_ATTACKER
|
||||
switchindataupdate BS_ATTACKER
|
||||
hpthresholds BS_ATTACKER
|
||||
trytoclearprimalweather
|
||||
printstring STRINGID_EMPTYSTRING3
|
||||
waitmessage 1
|
||||
printstring STRINGID_SWITCHINMON
|
||||
switchinanim BS_ATTACKER, TRUE
|
||||
waitstate
|
||||
switchineffects BS_ATTACKER
|
||||
BattleScript_EffectTeleportNewEnd:
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectBeatUp::
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
||||
|
@ -212,6 +212,7 @@ struct SideTimer
|
||||
u8 toxicSpikesAmount;
|
||||
u8 stealthRockAmount;
|
||||
u8 stickyWebAmount;
|
||||
u8 stickyWebBattlerId;
|
||||
u8 stickyWebBattlerSide; // Used for Court Change
|
||||
u8 auroraVeilTimer;
|
||||
u8 auroraVeilBattlerId;
|
||||
@ -652,7 +653,6 @@ struct BattleStruct
|
||||
u8 forcedSwitch:4; // For each battler
|
||||
u8 switchInAbilityPostponed:4; // To not activate against an empty field, each bit for battler
|
||||
u8 ballSpriteIds[2]; // item gfx, window gfx
|
||||
u8 stickyWebUser;
|
||||
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
|
||||
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
|
||||
// When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without.
|
||||
|
@ -211,14 +211,12 @@ void BufferStatChange(u8 battlerId, u8 statId, u8 stringId);
|
||||
bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef, bool32 checkTarget);
|
||||
u16 GetUsedHeldItem(u8 battler);
|
||||
bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags);
|
||||
u32 ApplyWeatherDamageMultiplier(u8 battlerAtk, u16 move, u8 moveType, u32 dmg, u16 holdEffectAtk, u16 holdEffectDef);
|
||||
u32 GetBattlerMoveTargetType(u8 battlerId, u16 move);
|
||||
bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move);
|
||||
bool8 IsMoveAffectedByParentalBond(u16 move, u8 battlerId);
|
||||
void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon);
|
||||
void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon);
|
||||
void RecalcBattlerStats(u32 battler, struct Pokemon *mon);
|
||||
void MulModifier(u16 *modifier, u16 val);
|
||||
bool32 IsAlly(u32 battlerAtk, u32 battlerDef);
|
||||
|
||||
// Ability checks
|
||||
@ -247,9 +245,4 @@ u8 GetBattlerGender(u8 battlerId);
|
||||
bool8 AreBattlersOfOppositeGender(u8 battler1, u8 battler2);
|
||||
u32 CalcSecondaryEffectChance(u8 battlerId, u8 secondaryEffectChance);
|
||||
|
||||
static inline u32 ApplyModifier(uq4_12_t modifier, u32 val)
|
||||
{
|
||||
return UQ_4_12_TO_INT((modifier * val) + UQ_4_12_ROUND);
|
||||
}
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
@ -52,10 +52,30 @@ static inline uq4_12_t uq4_12_multiply(uq4_12_t a, uq4_12_t b)
|
||||
return (product + UQ_4_12_ROUND) >> UQ_4_12_SHIFT;
|
||||
}
|
||||
|
||||
static inline uq4_12_t uq4_12_multiply_half_down(uq4_12_t a, uq4_12_t b)
|
||||
{
|
||||
u32 product = (u32) a * b;
|
||||
return (product + UQ_4_12_ROUND - 1) >> UQ_4_12_SHIFT;
|
||||
}
|
||||
|
||||
static inline uq4_12_t uq4_12_divide(uq4_12_t dividend, uq4_12_t divisor)
|
||||
{
|
||||
if (divisor == UQ_4_12(0.0)) return UQ_4_12(0);
|
||||
return (dividend << UQ_4_12_SHIFT) / divisor;
|
||||
}
|
||||
|
||||
// Multiplies value by the UQ_4_12 number modifier.
|
||||
// Returns an integer, rounded to nearest (rounding down on n.5)
|
||||
static inline u32 uq4_12_multiply_by_int_half_down(uq4_12_t modifier, u32 value)
|
||||
{
|
||||
return UQ_4_12_TO_INT((modifier * value) + UQ_4_12_ROUND - 1);
|
||||
}
|
||||
|
||||
// Multiplies value by the UQ_4_12 number modifier.
|
||||
// Returns an integer, rounded to nearest (rounding up on n.5)
|
||||
static inline u32 uq4_12_multiply_by_int_half_up(uq4_12_t modifier, u32 value)
|
||||
{
|
||||
return UQ_4_12_TO_INT((modifier * value) + UQ_4_12_ROUND);
|
||||
}
|
||||
|
||||
#endif // FPMATH_H_
|
||||
|
@ -151,7 +151,7 @@ static void InitSinglePlayerBtlControllers(void)
|
||||
|
||||
gBattlerPartyIndexes[0] = 0;
|
||||
gBattlerPartyIndexes[1] = 0;
|
||||
if (BATTLE_TWO_VS_ONE_OPPONENT)
|
||||
if (BATTLE_TWO_VS_ONE_OPPONENT || WILD_DOUBLE_BATTLE)
|
||||
{
|
||||
gBattlerPartyIndexes[2] = 3;
|
||||
gBattlerPartyIndexes[3] = 1;
|
||||
|
@ -3188,7 +3188,10 @@ static void BattleStartClearSetData(void)
|
||||
gBattleStruct->mega.triggerSpriteId = 0xFF;
|
||||
gBattleStruct->burst.triggerSpriteId = 0xFF;
|
||||
|
||||
gBattleStruct->stickyWebUser = 0xFF;
|
||||
for (i = 0; i < ARRAY_COUNT(gSideTimers); i++)
|
||||
{
|
||||
gSideTimers[i].stickyWebBattlerId = 0xFF;
|
||||
}
|
||||
gBattleStruct->appearedInBattle = 0;
|
||||
gBattleStruct->beatUpSlot = 0;
|
||||
|
||||
@ -3294,8 +3297,12 @@ void SwitchInClearSetData(void)
|
||||
gBattleStruct->lastMoveFailed &= ~(gBitTable[gActiveBattler]);
|
||||
gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]);
|
||||
|
||||
if (gActiveBattler == gBattleStruct->stickyWebUser)
|
||||
gBattleStruct->stickyWebUser = 0xFF; // Switched into sticky web user slot so reset it
|
||||
for (i = 0; i < ARRAY_COUNT(gSideTimers); i++)
|
||||
{
|
||||
// Switched into sticky web user slot, so reset stored battler ID
|
||||
if (gSideTimers[i].stickyWebBattlerId == gActiveBattler)
|
||||
gSideTimers[i].stickyWebBattlerId = 0xFF;
|
||||
}
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
@ -3408,8 +3415,12 @@ void FaintClearSetData(void)
|
||||
|
||||
gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]);
|
||||
|
||||
if (gActiveBattler == gBattleStruct->stickyWebUser)
|
||||
gBattleStruct->stickyWebUser = 0xFF; // User of sticky web fainted, so reset the stored battler ID
|
||||
for (i = 0; i < ARRAY_COUNT(gSideTimers); i++)
|
||||
{
|
||||
// User of sticky web fainted, so reset the stored battler ID
|
||||
if (gSideTimers[i].stickyWebBattlerId == gActiveBattler)
|
||||
gSideTimers[i].stickyWebBattlerId = 0xFF;
|
||||
}
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
@ -4605,7 +4616,11 @@ static void HandleTurnActionSelectionState(void)
|
||||
{
|
||||
// if we choose to throw a ball with our second mon, skip the action of the first
|
||||
// (if we have chosen throw ball with first, second's is already skipped)
|
||||
gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] = B_ACTION_NOTHING_FAINTED;
|
||||
// if throwing a ball in a wild battle with an in-game partner, skip partner's turn when throwing a ball
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||
gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)] = B_ACTION_NOTHING_FAINTED;
|
||||
else
|
||||
gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] = B_ACTION_NOTHING_FAINTED;
|
||||
}
|
||||
|
||||
gBattleMainFunc = SetActionsAndBattlersTurnOrder;
|
||||
|
@ -142,8 +142,8 @@ static const u8 sText_PkmnRaisedSpDefALittle[] = _("{B_ATK_PREFIX2}'s {B_CURRENT
|
||||
static const u8 sText_PkmnRaisedDef[] = _("{B_ATK_PREFIX2}'s {B_CURRENT_MOVE}\nraised DEFENSE!");
|
||||
static const u8 sText_PkmnRaisedDefALittle[] = _("{B_ATK_PREFIX2}'s {B_CURRENT_MOVE}\nraised DEFENSE a little!");
|
||||
static const u8 sText_PkmnCoveredByVeil[] = _("{B_ATK_PREFIX2}'s party is covered\nby a veil!");
|
||||
static const u8 sText_PkmnUsedSafeguard[] = _("{B_DEF_NAME_WITH_PREFIX}'s party is protected\nby SAFEGUARD!");
|
||||
static const u8 sText_PkmnSafeguardExpired[] = _("{B_ATK_PREFIX3}'s party is no longer\nprotected by SAFEGUARD!");
|
||||
static const u8 sText_PkmnUsedSafeguard[] = _("{B_DEF_NAME_WITH_PREFIX}'s party is protected\nby Safeguard!");
|
||||
static const u8 sText_PkmnSafeguardExpired[] = _("{B_ATK_PREFIX3}'s party is no longer\nprotected by Safeguard!");
|
||||
static const u8 sText_PkmnWentToSleep[] = _("{B_ATK_NAME_WITH_PREFIX} went\nto sleep!");
|
||||
static const u8 sText_PkmnSleptHealthy[] = _("{B_ATK_NAME_WITH_PREFIX} slept and\nbecame healthy!");
|
||||
static const u8 sText_PkmnWhippedWhirlwind[] = _("{B_ATK_NAME_WITH_PREFIX} whipped\nup a whirlwind!");
|
||||
@ -2705,7 +2705,7 @@ void BufferStringBattle(u16 stringID)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY)
|
||||
stringPtr = sText_LegendaryPkmnAppeared;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(gActiveBattler)]])) // interesting, looks like they had something planned for wild double battles
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]]))
|
||||
stringPtr = sText_TwoWildPkmnAppeared;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL)
|
||||
stringPtr = sText_WildPkmnAppearedPause;
|
||||
|
@ -1414,7 +1414,7 @@ static void Cmd_attackcanceler(void)
|
||||
return;
|
||||
}
|
||||
|
||||
// Z-moves and Max Moves bypass protection, but deal reduced damage (factored in CalcFinalDmg)
|
||||
// Z-moves and Max Moves bypass protection, but deal reduced damage (factored in AccumulateOtherModifiers)
|
||||
if (gBattleStruct->zmove.active && IS_BATTLER_PROTECTED(gBattlerTarget))
|
||||
{
|
||||
BattleScriptPush(cmd->nextInstr);
|
||||
@ -8551,8 +8551,9 @@ static bool32 IsTeatimeAffected(u32 battlerId)
|
||||
|
||||
#define UPDATE_COURTCHANGED_BATTLER(structField)\
|
||||
{ \
|
||||
sideTimerPlayer->structField ^= BIT_SIDE; \
|
||||
sideTimerOpp->structField ^= BIT_SIDE; \
|
||||
temp = sideTimerPlayer->structField; \
|
||||
sideTimerPlayer->structField = BATTLE_OPPOSITE(sideTimerOpp->structField); \
|
||||
sideTimerOpp->structField = BATTLE_OPPOSITE(temp); \
|
||||
} \
|
||||
|
||||
static bool32 CourtChangeSwapSideStatuses(void)
|
||||
@ -8587,9 +8588,7 @@ static bool32 CourtChangeSwapSideStatuses(void)
|
||||
UPDATE_COURTCHANGED_BATTLER(auroraVeilBattlerId);
|
||||
UPDATE_COURTCHANGED_BATTLER(tailwindBattlerId);
|
||||
UPDATE_COURTCHANGED_BATTLER(luckyChantBattlerId);
|
||||
|
||||
// For Mirror Armor only
|
||||
gBattleStruct->stickyWebUser = gBattlerAttacker;
|
||||
UPDATE_COURTCHANGED_BATTLER(stickyWebBattlerId);
|
||||
|
||||
// Track which side originally set the Sticky Web
|
||||
SWAP(sideTimerPlayer->stickyWebBattlerSide, sideTimerOpp->stickyWebBattlerSide, temp);
|
||||
@ -8633,33 +8632,6 @@ static void HandleScriptMegaPrimalBurst(u32 caseId, u32 battlerId, u32 type)
|
||||
}
|
||||
}
|
||||
|
||||
static bool32 CanTeleport(u8 battlerId)
|
||||
{
|
||||
struct Pokemon *party = GetBattlerParty(battlerId);
|
||||
u32 species, count, i;
|
||||
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
species = GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG);
|
||||
if (species != SPECIES_NONE && species != SPECIES_EGG && GetMonData(&party[i], MON_DATA_HP) != 0)
|
||||
count++;
|
||||
}
|
||||
|
||||
switch (GetBattlerSide(battlerId))
|
||||
{
|
||||
case B_SIDE_OPPONENT:
|
||||
if (count == 1 || gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
return FALSE;
|
||||
break;
|
||||
case B_SIDE_PLAYER:
|
||||
if (count == 1 || (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && count <= 2))
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Return True if the order was changed, and false if the order was not changed(for example because the target would move after the attacker anyway).
|
||||
static bool32 ChangeOrderTargetAfterAttacker(void)
|
||||
{
|
||||
@ -10615,8 +10587,8 @@ static void Cmd_various(void)
|
||||
// If Pokémon which set up Sticky Web is not on the field, no Pokémon have their Speed lowered."
|
||||
gBattlerAttacker = gBattlerTarget; // Initialize 'fail' condition
|
||||
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
|
||||
if (gBattleStruct->stickyWebUser != 0xFF)
|
||||
gBattlerAttacker = gBattleStruct->stickyWebUser;
|
||||
if (gSideTimers[GetBattlerSide(gActiveBattler)].stickyWebBattlerId != 0xFF)
|
||||
gBattlerAttacker = gSideTimers[GetBattlerSide(gActiveBattler)].stickyWebBattlerId;
|
||||
break;
|
||||
}
|
||||
case VARIOUS_CUT_1_3_HP_RAISE_STATS:
|
||||
@ -13878,9 +13850,9 @@ static void Cmd_setstickyweb(void)
|
||||
else
|
||||
{
|
||||
gSideStatuses[targetSide] |= SIDE_STATUS_STICKY_WEB;
|
||||
gSideTimers[targetSide].stickyWebBattlerId = gBattlerAttacker; // For Mirror Armor
|
||||
gSideTimers[targetSide].stickyWebBattlerSide = GetBattlerSide(gBattlerAttacker); // For Court Change/Defiant - set this to the user's side
|
||||
gSideTimers[targetSide].stickyWebAmount = 1;
|
||||
gBattleStruct->stickyWebUser = gBattlerAttacker; // For Mirror Armor
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
@ -16145,13 +16117,6 @@ void BS_GetBattlerSide(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_CanTeleport(void)
|
||||
{
|
||||
NATIVE_ARGS(u8 battler);
|
||||
gBattleCommunication[0] = CanTeleport(cmd->battler);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_TrySymbiosis(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
|
File diff suppressed because it is too large
Load Diff
0
src/script_pokemon_util.c
Executable file → Normal file
0
src/script_pokemon_util.c
Executable file → Normal file
@ -26,7 +26,7 @@ SINGLE_BATTLE_TEST("Contrary raises Attack when Intimidated", s16 damage)
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
}
|
||||
FINALLY {
|
||||
EXPECT_MUL_EQ(results[1].damage, Q_4_12(2.125), results[0].damage);
|
||||
EXPECT_MUL_EQ(results[1].damage, Q_4_12(2.25), results[0].damage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,15 +36,24 @@ SINGLE_BATTLE_TEST("Dry Skin increases damage taken from Fire-type moves by 25%"
|
||||
PARAMETRIZE { ability = ABILITY_DRY_SKIN; }
|
||||
GIVEN {
|
||||
ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PARASECT) { Ability(ability); }
|
||||
ASSUME(gBattleMoves[MOVE_EMBER].power == 40);
|
||||
ASSUME(gSpeciesInfo[SPECIES_PARASECT].types[0] == TYPE_BUG);
|
||||
ASSUME(gSpeciesInfo[SPECIES_PARASECT].types[1] == TYPE_GRASS);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] == TYPE_PSYCHIC);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] == TYPE_PSYCHIC);
|
||||
PLAYER(SPECIES_WOBBUFFET) { SpAttack(71); }
|
||||
OPPONENT(SPECIES_PARASECT) { Ability(ability); SpDefense(165); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_EMBER); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Ember!");
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.25), results[1].damage);
|
||||
// Due to numerics related to rounding on each applied multiplier,
|
||||
// the ability effect doesn't manifest as a 25% damage increase, but as a ~31% damage increase in this case.
|
||||
// Values obtained from https://calc.pokemonshowdown.com (Neutral nature and 0 IVs on both sides)
|
||||
EXPECT_EQ(results[0].damage, 52);
|
||||
EXPECT_EQ(results[1].damage, 68);
|
||||
}
|
||||
}
|
||||
|
||||
|
66
test/ability_fluffy.c
Normal file
66
test/ability_fluffy.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include "global.h"
|
||||
#include "test_battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gBattleMoves[MOVE_TACKLE].makesContact);
|
||||
ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE);
|
||||
ASSUME(gBattleMoves[MOVE_TACKLE].makesContact);
|
||||
ASSUME(gBattleMoves[MOVE_FIRE_PUNCH].makesContact);
|
||||
ASSUME(gBattleMoves[MOVE_FIRE_PUNCH].type == TYPE_FIRE);
|
||||
ASSUME(P_GEN_7_POKEMON == TRUE);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Fluffy halves damage taken from moves that make direct contact", s16 damage)
|
||||
{
|
||||
u32 ability;
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; }
|
||||
PARAMETRIZE { ability = ABILITY_FLUFFY; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_STUFFUL) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Tackle!");
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(0.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Fluffy doubles damage taken from fire type moves", s16 damage)
|
||||
{
|
||||
u32 ability;
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; }
|
||||
PARAMETRIZE { ability = ABILITY_FLUFFY; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_STUFFUL) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_EMBER); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Ember!");
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Fluffy does not alter damage of fire-type moves that make direct contact", s16 damage)
|
||||
{
|
||||
u32 ability;
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; }
|
||||
PARAMETRIZE { ability = ABILITY_FLUFFY; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_STUFFUL) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FIRE_PUNCH); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Fire Punch!");
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_EQ(results[0].damage, results[1].damage);
|
||||
}
|
||||
}
|
202
test/ability_mirror_armor.c
Normal file
202
test/ability_mirror_armor.c
Normal file
@ -0,0 +1,202 @@
|
||||
#include "global.h"
|
||||
#include "test_battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Mirror Armor lowers a stat of the attacking pokemon")
|
||||
{
|
||||
u16 move, statId;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LEER; statId = STAT_DEF; }
|
||||
PARAMETRIZE { move = MOVE_GROWL; statId = STAT_ATK; }
|
||||
PARAMETRIZE { move = MOVE_SWEET_SCENT; statId = STAT_EVASION; }
|
||||
PARAMETRIZE { move = MOVE_SAND_ATTACK; statId = STAT_ACC; }
|
||||
PARAMETRIZE { move = MOVE_CONFIDE; statId = STAT_SPATK; }
|
||||
PARAMETRIZE { move = MOVE_FAKE_TEARS; statId = STAT_SPDEF; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR);}
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
switch (statId)
|
||||
{
|
||||
case STAT_DEF:
|
||||
MESSAGE("Foe Wynaut's Defense fell!");
|
||||
break;
|
||||
case STAT_ATK:
|
||||
MESSAGE("Foe Wynaut's Attack fell!");
|
||||
break;
|
||||
case STAT_EVASION:
|
||||
MESSAGE("Foe Wynaut's evasiveness harshly fell!");
|
||||
break;
|
||||
case STAT_ACC:
|
||||
MESSAGE("Foe Wynaut's accuracy fell!");
|
||||
break;
|
||||
case STAT_SPATK:
|
||||
MESSAGE("Foe Wynaut's Sp. Atk fell!");
|
||||
break;
|
||||
case STAT_SPDEF:
|
||||
MESSAGE("Foe Wynaut's Sp. Def harshly fell!");
|
||||
break;
|
||||
}
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[statId], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[statId], (statId == STAT_SPDEF || statId == STAT_EVASION) ? DEFAULT_STAT_STAGE - 2 : DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Mirror Armor triggers even if the attacking Pokemon also has Mirror Armor ability")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||
OPPONENT(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_LEER); }
|
||||
} SCENE {
|
||||
MESSAGE("Foe Corviknigh used Leer!");
|
||||
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Corviknigh's Defense fell!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Mirror Armor doesn't lower the stats of an attacking Pokemon with the Clear Body ability")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||
OPPONENT(SPECIES_WYNAUT) { Ability(ABILITY_CLEAR_BODY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_LEER); }
|
||||
} SCENE {
|
||||
MESSAGE("Foe Wynaut used Leer!");
|
||||
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||
ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY);
|
||||
MESSAGE("Foe Wynaut's Clear Body prevents stat loss!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Mirror Armor lowers the Attack of Pokemon with Intimidate")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||
OPPONENT(SPECIES_GYARADOS) { Ability(ABILITY_INTIMIDATE); }
|
||||
} WHEN {
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Gyarados's Attack fell!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Unsure whether this should or should not fail, as Showdown has conflicting information. Needs testing in gen8 games.
|
||||
SINGLE_BATTLE_TEST("Mirror Armor doesn't lower the stats of an attacking Pokemon behind Substitute")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SUBSTITUTE); }
|
||||
TURN { MOVE(opponent, MOVE_LEER); }
|
||||
} SCENE {
|
||||
MESSAGE("Foe Wynaut used Substitute!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
|
||||
MESSAGE("Foe Wynaut used Leer!");
|
||||
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Mirror Armor raises the stat of an attacking Pokemon with Contrary")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR);}
|
||||
OPPONENT(SPECIES_SHUCKLE) {Ability(ABILITY_CONTRARY);}
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_LEER); }
|
||||
} SCENE {
|
||||
MESSAGE("Foe Shuckle used Leer!");
|
||||
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Shuckle's Defense rose!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Mirror Armor doesn't lower the stat of the attacking Pokemon if it is already at -6")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR);}
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCREECH); }
|
||||
TURN { MOVE(player, MOVE_SCREECH); }
|
||||
TURN { MOVE(player, MOVE_SCREECH); }
|
||||
TURN { MOVE(opponent, MOVE_LEER); }
|
||||
} SCENE {
|
||||
MESSAGE("Corviknigh used Screech!");
|
||||
MESSAGE("Corviknigh used Screech!");
|
||||
MESSAGE("Corviknigh used Screech!");
|
||||
MESSAGE("Foe Wynaut used Leer!");
|
||||
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Wynaut's Defense won't go lower!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], MIN_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
// This behaviour needs to be verified in the actual games. Currently it's written to follow Showdown's logic.
|
||||
DOUBLE_BATTLE_TEST("Mirror Armor lowers Speed of the partner Pokemon after Court Change was used by the opponent after it set up Sticky Web")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
ASSUME(gBattleMoves[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB);
|
||||
ASSUME(gBattleMoves[MOVE_COURT_CHANGE].effect == EFFECT_COURT_CHANGE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_STICKY_WEB); }
|
||||
TURN { MOVE(opponentLeft, MOVE_COURT_CHANGE); }
|
||||
TURN { SWITCH(playerRight, 2);}
|
||||
TURN { }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Sticky Web!");
|
||||
MESSAGE("Foe Wynaut used Court Change!");
|
||||
MESSAGE("Foe Wynaut swapped the battle effects affecting each side!");
|
||||
MESSAGE("Go! Corviknigh!");
|
||||
MESSAGE("Corviknigh was caught in a Sticky Web!");
|
||||
ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
MESSAGE("Wobbuffet's Speed fell!");
|
||||
}
|
||||
}
|
@ -8,13 +8,21 @@ SINGLE_BATTLE_TEST("Swarm boosts Bug-type moves in a pinch", s16 damage)
|
||||
PARAMETRIZE { hp = 33; }
|
||||
GIVEN {
|
||||
ASSUME(gBattleMoves[MOVE_BUG_BITE].type == TYPE_BUG);
|
||||
PLAYER(SPECIES_LEDYBA) { Ability(ABILITY_SWARM); MaxHP(99); HP(hp); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
ASSUME(gBattleMoves[MOVE_BUG_BITE].power == 60);
|
||||
ASSUME(gSpeciesInfo[SPECIES_LEDYBA].types[0] == TYPE_BUG);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] == TYPE_PSYCHIC);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] == TYPE_PSYCHIC);
|
||||
PLAYER(SPECIES_LEDYBA) { Ability(ABILITY_SWARM); MaxHP(99); HP(hp); Attack(45); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Defense(121); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_BUG_BITE); }
|
||||
} SCENE {
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
||||
// Due to numerics related to rounding on each applied multiplier,
|
||||
// the 50% move power increase doesn't manifest as a 50% damage increase, but as a 44% damage increase in this case.
|
||||
// Values obtained from https://calc.pokemonshowdown.com (Neutral nature and 0 IVs on both sides)
|
||||
EXPECT_EQ(results[0].damage, 50);
|
||||
EXPECT_EQ(results[1].damage, 72);
|
||||
}
|
||||
}
|
||||
|
78
test/damage_formula.c
Normal file
78
test/damage_formula.c
Normal file
@ -0,0 +1,78 @@
|
||||
#include "global.h"
|
||||
#include "test_battle.h"
|
||||
|
||||
// From https://bulbapedia.bulbagarden.net/wiki/Damage#Example
|
||||
|
||||
SINGLE_BATTLE_TEST("Damage calculation matches Gen5+")
|
||||
{
|
||||
s16 dmg;
|
||||
s16 expectedDamage;
|
||||
PARAMETRIZE { expectedDamage = 196; }
|
||||
PARAMETRIZE { expectedDamage = 192; }
|
||||
PARAMETRIZE { expectedDamage = 192; }
|
||||
PARAMETRIZE { expectedDamage = 192; }
|
||||
PARAMETRIZE { expectedDamage = 184; }
|
||||
PARAMETRIZE { expectedDamage = 184; }
|
||||
PARAMETRIZE { expectedDamage = 184; }
|
||||
PARAMETRIZE { expectedDamage = 180; }
|
||||
PARAMETRIZE { expectedDamage = 180; }
|
||||
PARAMETRIZE { expectedDamage = 180; }
|
||||
PARAMETRIZE { expectedDamage = 172; }
|
||||
PARAMETRIZE { expectedDamage = 172; }
|
||||
PARAMETRIZE { expectedDamage = 172; }
|
||||
PARAMETRIZE { expectedDamage = 168; }
|
||||
PARAMETRIZE { expectedDamage = 168; }
|
||||
PARAMETRIZE { expectedDamage = 168; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GLACEON) { Level(75); Attack(123); }
|
||||
OPPONENT(SPECIES_GARCHOMP) { Defense(163); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(player, MOVE_ICE_FANG, WITH_RNG(RNG_DAMAGE_MODIFIER, i));
|
||||
}
|
||||
}
|
||||
SCENE{
|
||||
MESSAGE("Glaceon used Ice Fang!");
|
||||
HP_BAR(opponent, captureDamage: &dmg);
|
||||
}
|
||||
THEN{
|
||||
EXPECT_EQ(expectedDamage, dmg);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Damage calculation matches Gen5+ (Muscle Band, crit)")
|
||||
{
|
||||
s16 dmg;
|
||||
s16 expectedDamage;
|
||||
PARAMETRIZE { expectedDamage = 324; }
|
||||
PARAMETRIZE { expectedDamage = 316; }
|
||||
PARAMETRIZE { expectedDamage = 312; }
|
||||
PARAMETRIZE { expectedDamage = 312; }
|
||||
PARAMETRIZE { expectedDamage = 304; }
|
||||
PARAMETRIZE { expectedDamage = 304; }
|
||||
PARAMETRIZE { expectedDamage = 300; }
|
||||
PARAMETRIZE { expectedDamage = 300; }
|
||||
PARAMETRIZE { expectedDamage = 292; }
|
||||
PARAMETRIZE { expectedDamage = 292; }
|
||||
PARAMETRIZE { expectedDamage = 288; }
|
||||
PARAMETRIZE { expectedDamage = 288; }
|
||||
PARAMETRIZE { expectedDamage = 280; }
|
||||
PARAMETRIZE { expectedDamage = 276; }
|
||||
PARAMETRIZE { expectedDamage = 276; }
|
||||
PARAMETRIZE { expectedDamage = 268; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GLACEON) { Level(75); Attack(123); Item(ITEM_MUSCLE_BAND); }
|
||||
OPPONENT(SPECIES_GARCHOMP) { Defense(163); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(player, MOVE_ICE_FANG, WITH_RNG(RNG_DAMAGE_MODIFIER, i), criticalHit: TRUE);
|
||||
}
|
||||
}
|
||||
SCENE{
|
||||
MESSAGE("Glaceon used Ice Fang!");
|
||||
HP_BAR(opponent, captureDamage: &dmg);
|
||||
}
|
||||
THEN{
|
||||
EXPECT_EQ(expectedDamage, dmg);
|
||||
}
|
||||
}
|
@ -112,7 +112,7 @@ SINGLE_BATTLE_TEST("Berserk Gene does not confuse when Safeguard is active")
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Using Berserk Gene, the Attack of Wobbuffet sharply rose!");
|
||||
MESSAGE("Wobbuffet's party is protected by SAFEGUARD!");
|
||||
MESSAGE("Wobbuffet's party is protected by Safeguard!");
|
||||
NOT MESSAGE("Wobbuffet became confused!");
|
||||
}
|
||||
}
|
||||
|
153
test/move_effect_court_change.c
Normal file
153
test/move_effect_court_change.c
Normal file
@ -0,0 +1,153 @@
|
||||
#include "global.h"
|
||||
#include "test_battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gBattleMoves[MOVE_COURT_CHANGE].effect == EFFECT_COURT_CHANGE);
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Court Change swaps entry hazards used by the opponent")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); MOVE(opponentRight, MOVE_STEALTH_ROCK); }
|
||||
TURN { MOVE(opponentLeft, MOVE_SPIKES); MOVE(opponentRight, MOVE_TOXIC_SPIKES); }
|
||||
TURN { MOVE(playerLeft, MOVE_COURT_CHANGE); }
|
||||
TURN { SWITCH(playerLeft, 2); SWITCH(opponentLeft, 2); }
|
||||
} SCENE {
|
||||
MESSAGE("Foe Wobbuffet used Sticky Web!");
|
||||
MESSAGE("Foe Wobbuffet used Stealth Rock!");
|
||||
MESSAGE("Foe Wobbuffet used Spikes!");
|
||||
MESSAGE("Foe Wobbuffet used Toxic Spikes!");
|
||||
MESSAGE("Wynaut used Court Change!");
|
||||
MESSAGE("Wynaut swapped the battle effects affecting each side!");
|
||||
MESSAGE("Go! Wynaut!");
|
||||
NONE_OF {
|
||||
MESSAGE("Wynaut is hurt by spikes!");
|
||||
MESSAGE("Pointed stones dug into Wynaut!");
|
||||
MESSAGE("Wynaut was poisoned!");
|
||||
MESSAGE("Wynaut was caught in a Sticky Web!");
|
||||
}
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
MESSAGE("Foe Wobbuffet is hurt by spikes!");
|
||||
MESSAGE("Pointed stones dug into Foe Wobbuffet!");
|
||||
MESSAGE("Foe Wobbuffet was poisoned!");
|
||||
MESSAGE("Foe Wobbuffet was caught in a Sticky Web!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Court Change swaps entry hazards used by the player")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_STICKY_WEB); MOVE(playerRight, MOVE_STEALTH_ROCK); }
|
||||
TURN { MOVE(playerLeft, MOVE_SPIKES); MOVE(playerRight, MOVE_TOXIC_SPIKES); }
|
||||
TURN { MOVE(opponentLeft, MOVE_COURT_CHANGE); }
|
||||
TURN { SWITCH(opponentLeft, 2); SWITCH(playerLeft, 2); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Sticky Web!");
|
||||
MESSAGE("Wobbuffet used Stealth Rock!");
|
||||
MESSAGE("Wobbuffet used Spikes!");
|
||||
MESSAGE("Wobbuffet used Toxic Spikes!");
|
||||
MESSAGE("Foe Wynaut used Court Change!");
|
||||
MESSAGE("Foe Wynaut swapped the battle effects affecting each side!");
|
||||
MESSAGE("Go! Wobbuffet!");
|
||||
MESSAGE("Wobbuffet is hurt by spikes!");
|
||||
MESSAGE("Pointed stones dug into Wobbuffet!");
|
||||
MESSAGE("Wobbuffet was poisoned!");
|
||||
MESSAGE("Wobbuffet was caught in a Sticky Web!");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
NONE_OF {
|
||||
MESSAGE("Foe Wynaut is hurt by spikes!");
|
||||
MESSAGE("Pointed stones dug into Foe Wynaut!");
|
||||
MESSAGE("Foe Wynaut was poisoned!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Court Change used by the player swaps Mist, Safeguard, Lucky Chant, Reflect, Light Screen, Tailwind")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_MIST); MOVE(opponentRight, MOVE_SAFEGUARD); }
|
||||
TURN { MOVE(opponentLeft, MOVE_LUCKY_CHANT); MOVE(opponentRight, MOVE_REFLECT); }
|
||||
TURN { MOVE(opponentLeft, MOVE_LIGHT_SCREEN); MOVE(opponentRight, MOVE_TAILWIND); }
|
||||
TURN { MOVE(playerLeft, MOVE_COURT_CHANGE); }
|
||||
TURN { }
|
||||
TURN { }
|
||||
TURN { }
|
||||
TURN { }
|
||||
} SCENE {
|
||||
MESSAGE("Foe Wobbuffet used Mist!");
|
||||
MESSAGE("Foe Wobbuffet used Safeguard!");
|
||||
MESSAGE("Foe Wobbuffet used Lucky Chant!");
|
||||
MESSAGE("Foe Wobbuffet used Reflect!");
|
||||
MESSAGE("Foe Wobbuffet used Light Screen!");
|
||||
MESSAGE("Foe Wobbuffet used Tailwind!");
|
||||
MESSAGE("Wynaut used Court Change!");
|
||||
MESSAGE("Wynaut swapped the battle effects affecting each side!");
|
||||
// The effects now end for the player side.
|
||||
MESSAGE("Ally's Mist wore off!");
|
||||
MESSAGE("Ally's party is no longer protected by Safeguard!");
|
||||
MESSAGE("Ally's Reflect wore off!");
|
||||
MESSAGE("Your team's Lucky Chant wore off!");
|
||||
MESSAGE("Your team's tailwind petered out!");
|
||||
MESSAGE("Ally's Light Screen wore off!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Court Change used by the opponent swaps Mist, Safeguard, Lucky Chant, Reflect, Light Screen, Tailwind")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_MIST); MOVE(playerRight, MOVE_SAFEGUARD); }
|
||||
TURN { MOVE(playerLeft, MOVE_LUCKY_CHANT); MOVE(playerRight, MOVE_REFLECT); }
|
||||
TURN { MOVE(playerLeft, MOVE_LIGHT_SCREEN); MOVE(playerRight, MOVE_TAILWIND); }
|
||||
TURN { MOVE(opponentLeft, MOVE_COURT_CHANGE); }
|
||||
TURN { }
|
||||
TURN { }
|
||||
TURN { }
|
||||
TURN { }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Mist!");
|
||||
MESSAGE("Wobbuffet used Safeguard!");
|
||||
MESSAGE("Wobbuffet used Lucky Chant!");
|
||||
MESSAGE("Wobbuffet used Reflect!");
|
||||
MESSAGE("Wobbuffet used Light Screen!");
|
||||
MESSAGE("Wobbuffet used Tailwind!");
|
||||
MESSAGE("Foe Wynaut used Court Change!");
|
||||
MESSAGE("Foe Wynaut swapped the battle effects affecting each side!");
|
||||
// The effects now end for the player side.
|
||||
MESSAGE("Foe's Mist wore off!");
|
||||
MESSAGE("Foe's party is no longer protected by Safeguard!");
|
||||
MESSAGE("Foe's Reflect wore off!");
|
||||
MESSAGE("The opposing team's Lucky Chant wore off!");
|
||||
MESSAGE("The opposing team's tailwind petered out!");
|
||||
MESSAGE("Foe's Light Screen wore off!");
|
||||
}
|
||||
}
|
@ -125,7 +125,7 @@ DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Mist and Safeguard
|
||||
STATUS_ICON(opponentRight, badPoison: TRUE);
|
||||
}
|
||||
else {
|
||||
MESSAGE("Foe Wobbuffet's party is protected by SAFEGUARD!");
|
||||
MESSAGE("Foe Wobbuffet's party is protected by Safeguard!");
|
||||
NOT STATUS_ICON(opponentRight, badPoison: TRUE);
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ ASSUMPTIONS
|
||||
|
||||
SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on miss")
|
||||
{
|
||||
s16 recoil;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@ -25,7 +24,6 @@ SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on miss")
|
||||
|
||||
SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on protect")
|
||||
{
|
||||
s16 recoil;
|
||||
GIVEN {
|
||||
ASSUME(!gBattleMoves[MOVE_JUMP_KICK].ignoresProtect);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
@ -55,3 +53,48 @@ SINGLE_BATTLE_TEST("Jump Kick has no recoil if no target")
|
||||
NOT HP_BAR(player, damage: maxHP / 2);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Jump Kick's recoil happens after Spiky Shield damage and Pokemon can faint from either of these")
|
||||
{
|
||||
s16 hp, maxHp = 256;
|
||||
bool32 faintOnSpiky = FALSE, faintOnJumpKick = FALSE;
|
||||
|
||||
PARAMETRIZE { hp = maxHp; }
|
||||
PARAMETRIZE { hp = maxHp / 2; faintOnJumpKick = TRUE; } // Faints after Jump Kick's recoil
|
||||
PARAMETRIZE { hp = maxHp / 8; faintOnSpiky = TRUE; } // Faints after Spiky Shield's recoil
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gBattleMoves[MOVE_SPIKY_SHIELD].effect == EFFECT_PROTECT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(hp); MaxHP(maxHp); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
if (!faintOnJumpKick && !faintOnSpiky) {
|
||||
TURN { MOVE(opponent, MOVE_SPIKY_SHIELD); MOVE(player, MOVE_JUMP_KICK, hit: FALSE); }
|
||||
} else {
|
||||
TURN { MOVE(opponent, MOVE_SPIKY_SHIELD); MOVE(player, MOVE_JUMP_KICK, hit: FALSE); SEND_OUT(player, 1); }
|
||||
}
|
||||
TURN { ; }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKY_SHIELD, opponent);
|
||||
MESSAGE("Wobbuffet used Jump Kick!");
|
||||
MESSAGE("Foe Wobbuffet protected itself!");
|
||||
HP_BAR(player, damage: maxHp / 8);
|
||||
MESSAGE("Wobbuffet was hurt by Foe Wobbuffet's Spiky Shield!");
|
||||
if (faintOnSpiky){
|
||||
MESSAGE("Wobbuffet fainted!");
|
||||
MESSAGE("Go! Wynaut!");
|
||||
NONE_OF {
|
||||
MESSAGE("Wobbuffet kept going and crashed!");
|
||||
HP_BAR(player);
|
||||
}
|
||||
} else {
|
||||
MESSAGE("Wobbuffet kept going and crashed!");
|
||||
HP_BAR(player);
|
||||
if (faintOnJumpKick) {
|
||||
MESSAGE("Wobbuffet fainted!");
|
||||
MESSAGE("Go! Wynaut!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
237
test/move_effect_sticky_web.c
Normal file
237
test/move_effect_sticky_web.c
Normal file
@ -0,0 +1,237 @@
|
||||
#include "global.h"
|
||||
#include "test_battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gBattleMoves[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sticky Web lowers Speed by 1 on switch-in")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STICKY_WEB); }
|
||||
TURN { SWITCH(opponent, 1); }
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, player);
|
||||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Wynaut's Speed fell!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sticky Web can only be set up 1 time")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STICKY_WEB); }
|
||||
TURN { MOVE(player, MOVE_STICKY_WEB); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, player);
|
||||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
|
||||
MESSAGE("Wobbuffet used Sticky Web!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, player);
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sticky Web lowers Speed by 1 in a double battle after Explosion fainting both mons")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gBattleMoves[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||
PLAYER(SPECIES_WOBBUFFET) {Speed(5);}
|
||||
PLAYER(SPECIES_WOBBUFFET) {HP(1500); Speed(10);}
|
||||
PLAYER(SPECIES_WOBBUFFET) {Speed(10);}
|
||||
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_STICKY_WEB); MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 2); SEND_OUT(opponentRight, 3); }
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, playerRight);
|
||||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Foe Wynaut's Speed fell!");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Foe Wynaut's Speed fell!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sticky Web raises Speed by 1 for a Pokemon with Contrary")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_SHUCKLE) { Ability(ABILITY_CONTRARY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STICKY_WEB); }
|
||||
TURN { SWITCH(opponent, 1); }
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, player);
|
||||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
MESSAGE("2 sent out Shuckle!");
|
||||
MESSAGE("Foe Shuckle was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Shuckle's Speed rose!");
|
||||
}
|
||||
}
|
||||
|
||||
#define BATTLER_OPPONENT (opponentSetUpper == 0 ? opponentLeft : opponentRight)
|
||||
#define BATTLER_PLAYER (playerSetUpper == 0 ? playerLeft : playerRight)
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - the battler which set up Sticky Web has its Speed lowered instead")
|
||||
{
|
||||
u8 playerSetUpper, opponentSetUpper; // 0 left, 1 right
|
||||
|
||||
PARAMETRIZE {playerSetUpper = 0; opponentSetUpper = 0; }
|
||||
PARAMETRIZE {playerSetUpper = 0; opponentSetUpper = 1; }
|
||||
PARAMETRIZE {playerSetUpper = 1; opponentSetUpper = 0; }
|
||||
PARAMETRIZE {playerSetUpper = 1; opponentSetUpper = 1; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||
PLAYER(SPECIES_SQUIRTLE);
|
||||
PLAYER(SPECIES_CHARMANDER);
|
||||
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); } // Iron Ball, so that flying type Corviknight is affected by Sticky Web.
|
||||
OPPONENT(SPECIES_CATERPIE);
|
||||
OPPONENT(SPECIES_WEEDLE);
|
||||
} WHEN {
|
||||
TURN { MOVE(BATTLER_OPPONENT, MOVE_STICKY_WEB); }
|
||||
TURN { MOVE(BATTLER_PLAYER, MOVE_STICKY_WEB); }
|
||||
TURN { SWITCH(playerRight, 2); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, BATTLER_OPPONENT);
|
||||
MESSAGE("A sticky web spreads out on the ground around your team!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, BATTLER_PLAYER);
|
||||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
|
||||
MESSAGE("Go! Corviknigh!");
|
||||
MESSAGE("Corviknigh was caught in a Sticky Web!");
|
||||
ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, BATTLER_OPPONENT);
|
||||
if (opponentSetUpper == 0) {
|
||||
MESSAGE("Foe Caterpie's Speed fell!");
|
||||
} else {
|
||||
MESSAGE("Foe Weedle's Speed fell!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef BATTLER_OPPONENT
|
||||
#undef BATTLER_PLAYER
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - no one has their Speed lowered if the set upper switched")
|
||||
{
|
||||
u16 speedPlayer, speedOpponent;
|
||||
|
||||
// We need to make sure Sticky Web user saves for both sides, so it doesn't matter who sets it first.
|
||||
PARAMETRIZE { speedPlayer = 5; speedOpponent = 10; }
|
||||
PARAMETRIZE { speedPlayer = 10; speedOpponent = 5; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||
PLAYER(SPECIES_SQUIRTLE) { Speed(speedPlayer); }
|
||||
PLAYER(SPECIES_CHARMANDER) { Speed(speedPlayer); }
|
||||
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); Speed(speedOpponent); } // Iron Ball, so that flying type Corviknight is affected by Sticky Web.
|
||||
OPPONENT(SPECIES_CATERPIE) { Speed(speedOpponent); }
|
||||
OPPONENT(SPECIES_WEEDLE) { Speed(speedOpponent); }
|
||||
OPPONENT(SPECIES_PIDGEY) { Speed(speedOpponent); } // Flying type,so not affected by Sticky Web.
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); MOVE(playerRight, MOVE_STICKY_WEB); }
|
||||
TURN { SWITCH(opponentLeft, 2); }
|
||||
TURN { SWITCH(playerRight, 2); }
|
||||
} SCENE {
|
||||
if (speedPlayer > speedOpponent) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, playerRight);
|
||||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft);
|
||||
MESSAGE("A sticky web spreads out on the ground around your team!");
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft);
|
||||
MESSAGE("A sticky web spreads out on the ground around your team!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, playerRight);
|
||||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
}
|
||||
|
||||
MESSAGE("Go! Corviknigh!");
|
||||
MESSAGE("Corviknigh was caught in a Sticky Web!");
|
||||
ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
} THEN {
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(playerRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - no one has their Speed lowered if the set upper fainted")
|
||||
{
|
||||
bool8 hasReplacement;
|
||||
|
||||
// We need to make sure Sticky Web user saves for both sides, so it doesn't matter who sets it first.
|
||||
PARAMETRIZE {hasReplacement = TRUE;}
|
||||
PARAMETRIZE {hasReplacement = FALSE;}
|
||||
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||
ASSUME(gBattleMoves[MOVE_MEMENTO].effect == EFFECT_MEMENTO);
|
||||
PLAYER(SPECIES_SQUIRTLE) {Speed(5); }
|
||||
PLAYER(SPECIES_CHARMANDER) {Speed(5); }
|
||||
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); Speed(5); } // Iron Ball, so that flying type Corviknight is affected by Sticky Web.
|
||||
OPPONENT(SPECIES_CATERPIE) {Speed(7); }
|
||||
OPPONENT(SPECIES_WEEDLE) {Speed(7); }
|
||||
if (hasReplacement) {
|
||||
OPPONENT(SPECIES_PIDGEY) {Speed(7); }
|
||||
}
|
||||
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); }
|
||||
if (hasReplacement) {
|
||||
TURN { MOVE(opponentLeft, MOVE_MEMENTO, target:playerLeft); SEND_OUT(opponentLeft, 2); }
|
||||
} else {
|
||||
TURN { MOVE(opponentLeft, MOVE_MEMENTO, target:playerLeft);}
|
||||
}
|
||||
TURN { SWITCH(playerRight, 2); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft);
|
||||
MESSAGE("A sticky web spreads out on the ground around your team!");
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MEMENTO, opponentLeft);
|
||||
MESSAGE("Foe Caterpie fainted!");
|
||||
if (hasReplacement) {
|
||||
MESSAGE("2 sent out Pidgey!");
|
||||
}
|
||||
|
||||
MESSAGE("Go! Corviknigh!");
|
||||
MESSAGE("Corviknigh was caught in a Sticky Web!");
|
||||
ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
} THEN {
|
||||
if (hasReplacement) {
|
||||
EXPECT_EQ(opponentLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(playerRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponentRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
61
test/move_effect_teleport.c
Normal file
61
test/move_effect_teleport.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include "global.h"
|
||||
#include "test_battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gBattleMoves[MOVE_TELEPORT].effect == EFFECT_TELEPORT);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Teleport fails when there is no pokemon to switch in")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TELEPORT); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Teleport fails when there no alive pokemon left")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT) { HP(0); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TELEPORT); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Teleport forces the pokemon to switch out")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TELEPORT); SEND_OUT(opponent, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TELEPORT, opponent);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Teleport does not fail if the user is trapped")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FIRE_SPIN); MOVE(opponent, MOVE_TELEPORT); SEND_OUT(opponent, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FIRE_SPIN, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TELEPORT, opponent);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
}
|
||||
}
|
90
test/status3.c
Normal file
90
test/status3.c
Normal file
@ -0,0 +1,90 @@
|
||||
#include "global.h"
|
||||
#include "test_battle.h"
|
||||
|
||||
ASSUMPTIONS {
|
||||
ASSUME(gBattleMoves[MOVE_MINIMIZE].effect == EFFECT_MINIMIZE);
|
||||
ASSUME(gBattleMoves[MOVE_STEAMROLLER].minimizeDoubleDamage);
|
||||
ASSUME(gBattleMoves[MOVE_EARTHQUAKE].damagesUnderground);
|
||||
ASSUME(gBattleMoves[MOVE_SURF].damagesUnderwater);
|
||||
ASSUME(gBattleMoves[MOVE_TWISTER].damagesAirborneDoubleDamage);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Minimize causes the target to take double damage from certain moves", s16 damage)
|
||||
{
|
||||
bool32 useMinimize;
|
||||
PARAMETRIZE { useMinimize = FALSE; }
|
||||
PARAMETRIZE { useMinimize = TRUE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
|
||||
} WHEN {
|
||||
if (useMinimize)
|
||||
TURN { MOVE(opponent, MOVE_MINIMIZE); MOVE(player, MOVE_STEAMROLLER); }
|
||||
else
|
||||
TURN { MOVE(player, MOVE_STEAMROLLER); }
|
||||
} SCENE {
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Being underground causes the target to take double damage from certain moves", s16 damage)
|
||||
{
|
||||
bool32 useDig;
|
||||
PARAMETRIZE { useDig = FALSE; }
|
||||
PARAMETRIZE { useDig = TRUE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
|
||||
} WHEN {
|
||||
if (useDig)
|
||||
TURN { MOVE(opponent, MOVE_DIG); MOVE(player, MOVE_EARTHQUAKE); }
|
||||
else
|
||||
TURN { MOVE(player, MOVE_EARTHQUAKE); }
|
||||
} SCENE {
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Being underwater causes the target to take double damage from certain moves", s16 damage)
|
||||
{
|
||||
bool32 useDive;
|
||||
PARAMETRIZE { useDive = FALSE; }
|
||||
PARAMETRIZE { useDive = TRUE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
|
||||
} WHEN {
|
||||
if (useDive)
|
||||
TURN { MOVE(opponent, MOVE_DIVE); MOVE(player, MOVE_SURF); }
|
||||
else
|
||||
TURN { MOVE(player, MOVE_SURF); }
|
||||
} SCENE {
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Being airborne causes the target to take double damage from certain moves", s16 damage)
|
||||
{
|
||||
bool32 useDive;
|
||||
PARAMETRIZE { useDive = FALSE; }
|
||||
PARAMETRIZE { useDive = TRUE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
|
||||
} WHEN {
|
||||
if (useDive)
|
||||
TURN { MOVE(opponent, MOVE_FLY); MOVE(player, MOVE_TWISTER); }
|
||||
else
|
||||
TURN { MOVE(player, MOVE_TWISTER); }
|
||||
} SCENE {
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage);
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
#include "global.h"
|
||||
#include "characters.h"
|
||||
#include "gpu_regs.h"
|
||||
#include "load_save.h"
|
||||
#include "main.h"
|
||||
#include "malloc.h"
|
||||
#include "random.h"
|
||||
@ -114,6 +115,10 @@ void CB2_TestRunner(void)
|
||||
return;
|
||||
}
|
||||
|
||||
MoveSaveBlocks_ResetHeap();
|
||||
ClearSav1();
|
||||
ClearSav2();
|
||||
|
||||
gIntrTable[7] = Intr_Timer2;
|
||||
|
||||
// The current test restarted the ROM (e.g. by jumping to NULL).
|
||||
|
@ -81,7 +81,6 @@ SINGLE_BATTLE_TEST("Snow halves the power of Solar Beam", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Snow halves the power of Solar Blade", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
KNOWN_FAILING; // fails bc the bp of solar blade gets rounded up which leads to slightly incorrect calcs down the line
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SNOWSCAPE; }
|
||||
GIVEN {
|
||||
|
Loading…
Reference in New Issue
Block a user