Merge branch 'master' of https://github.com/rh-hideout/pokeemerald-expansion into rh-hideout-master
This commit is contained in:
commit
18aeb5b256
@ -642,6 +642,24 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "LogicalLlama",
|
||||
"name": "LogicalLlama",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/248230900?v=4",
|
||||
"profile": "https://github.com/LogicalLlama",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "KnightGallade",
|
||||
"name": "KnightGallade",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/189022270?v=4",
|
||||
"profile": "https://github.com/KnightGallade",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
@ -92,6 +92,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<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>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ChrispyChris27"><img src="https://avatars.githubusercontent.com/u/173648816?v=4?s=100" width="100px;" alt="ChrispyChris27"/><br /><sub><b>ChrispyChris27</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=ChrispyChris27" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LogicalLlama"><img src="https://avatars.githubusercontent.com/u/248230900?v=4?s=100" width="100px;" alt="LogicalLlama"/><br /><sub><b>LogicalLlama</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/issues?q=author%3ALogicalLlama" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KnightGallade"><img src="https://avatars.githubusercontent.com/u/189022270?v=4?s=100" width="100px;" alt="KnightGallade"/><br /><sub><b>KnightGallade</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/issues?q=author%3AKnightGallade" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
|
||||
@ -25680,7 +25680,7 @@ SnoreEffect:
|
||||
playsewithpan SE_M_SNORE, SOUND_PAN_ATTACKER
|
||||
createvisualtask AnimTask_ScaleMonAndRestore, 5, -7, -7, 7, ANIM_ATTACKER, 1
|
||||
createvisualtask AnimTask_ShakeMon2, 2, ANIM_TARGET, 4, 0, 7, 1
|
||||
shake_mon_or_platform velocity=6, shake_timer=1, shake_duration=14, type=0, battler_selector=0
|
||||
shake_mon_or_platform velocity=6, shake_timer=1, shake_duration=14, type=0
|
||||
createsprite gSnoreZSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, -42, -38, 24, 0, 0
|
||||
createsprite gSnoreZSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 0, -42, 24, 0, 0
|
||||
createsprite gSnoreZSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 42, -38, 24, 0, 0
|
||||
|
||||
@ -1652,6 +1652,7 @@ BattleScript_ToxicThreadTryPsn::
|
||||
|
||||
BattleScript_EffectVenomDrench::
|
||||
attackcanceler
|
||||
jumpifsubstituteblocks BattleScript_ButItFailed
|
||||
jumpifstatus BS_TARGET, STATUS1_PSN_ANY, BattleScript_EffectVenomDrenchCanBeUsed
|
||||
goto BattleScript_ButItFailed
|
||||
BattleScript_EffectVenomDrenchCanBeUsed:
|
||||
@ -2302,6 +2303,7 @@ BattleScript_EffectMagicRoom::
|
||||
|
||||
BattleScript_EffectAquaRing::
|
||||
attackcanceler
|
||||
jumpifvolatile BS_ATTACKER, VOLATILE_AQUA_RING, BattleScript_ButItFailed
|
||||
setvolatile BS_ATTACKER, VOLATILE_AQUA_RING
|
||||
attackanimation
|
||||
waitanimation
|
||||
@ -4318,6 +4320,7 @@ BattleScript_EffectWaterSport::
|
||||
|
||||
BattleScript_EffectTickle::
|
||||
attackcanceler
|
||||
jumpifsubstituteblocks BattleScript_ButItFailed
|
||||
jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_ATK, MIN_STAT_STAGE, BattleScript_TickleDoMoveAnim
|
||||
jumpifstat BS_TARGET, CMP_EQUAL, STAT_DEF, MIN_STAT_STAGE, BattleScript_CantLowerMultipleStats
|
||||
BattleScript_TickleDoMoveAnim::
|
||||
@ -5320,9 +5323,7 @@ BattleScript_GulpMissileNoDmgGorging:
|
||||
handleformchange BS_TARGET, 0
|
||||
playanimation BS_TARGET, B_ANIM_FORM_CHANGE
|
||||
waitanimation
|
||||
swapattackerwithtarget
|
||||
seteffectprimary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_PARALYSIS
|
||||
swapattackerwithtarget
|
||||
seteffectprimary BS_TARGET, BS_ATTACKER, MOVE_EFFECT_PARALYSIS
|
||||
return
|
||||
BattleScript_GulpMissileNoSecondEffectGorging:
|
||||
handleformchange BS_TARGET, 0
|
||||
@ -5352,7 +5353,7 @@ BattleScript_GulpMissileNoDmgGulping:
|
||||
printfromtable gStatDownStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_GulpMissileGulpingEnd:
|
||||
swapattackerwithtarget @ restore the battlers, just in case
|
||||
swapattackerwithtarget
|
||||
return
|
||||
BattleScript_GulpMissileNoSecondEffectGulping:
|
||||
handleformchange BS_TARGET, 0
|
||||
|
||||
@ -61,6 +61,7 @@ struct DisableStruct
|
||||
{
|
||||
u32 transformedMonPersonality;
|
||||
bool8 transformedMonShininess;
|
||||
u16 transformedMonSpecies;
|
||||
u16 disabledMove;
|
||||
u16 encoredMove;
|
||||
u8 protectUses:4;
|
||||
|
||||
@ -115,11 +115,16 @@
|
||||
// Additionally, in gen8+ the Healing Wish's effect will be stored until the user switches into a statused or hurt mon.
|
||||
#define B_DEFOG_EFFECT_CLEARING GEN_LATEST // In Gen5+, Defog does not lower Evasion of target behind Subsitute. In Gen6+, Defog clears Spikes, Toxic Spikes, Stealth Rock and Sticky Web from both sides. In Gen8+, Defog also clears active Terrain.
|
||||
#define B_STOCKPILE_RAISES_DEFS GEN_LATEST // In Gen4+, Stockpile also raises Defense and Sp. Defense stats. Once Spit Up / Swallow is used, these stat changes are lost.
|
||||
#define B_TRANSFORM_SEMI_INV_FAIL GEN_LATEST // In Gen2+, Transform fails if the target is semi-invulnerable.
|
||||
#define B_TRANSFORM_TARGET_FAIL GEN_LATEST // In Gen2+, Transform fails if the target is already transformed.
|
||||
#define B_TRANSFORM_USER_FAIL GEN_LATEST // In Gen5+, Transform fails if the user is already transformed.
|
||||
#define B_TRANSFORM_SUBSTITUTE_FAIL GEN_LATEST // In Gen5+, Transform fails if the target is behind a Substitute.
|
||||
#define B_TRANSFORM_SHINY GEN_LATEST // In Gen4+, Transform will copy the shiny state of the opponent instead of maintaining its own shiny state.
|
||||
#define B_TRANSFORM_FORM_CHANGES GEN_LATEST // In Gen5+, Transformed Pokemon cannot change forms.
|
||||
#define B_WIDE_GUARD GEN_LATEST // In Gen5 only, Wide Guard has a chance to fail if used consecutively.
|
||||
#define B_QUICK_GUARD GEN_LATEST // In Gen5 only, Quick Guard has a chance to fail if used consecutively.
|
||||
#define B_IMPRISON GEN_LATEST // In Gen5+, Imprison doesn't fail if opposing pokemon don't have any moves the user knows.
|
||||
#define B_TAUNT_ME_FIRST GEN_LATEST // In Gen5+, Taunt does not block Me First.
|
||||
#define B_ALLY_SWITCH_FAIL_CHANCE GEN_LATEST // In Gen9+, using Ally Switch consecutively decreases the chance of success for each consecutive use.
|
||||
#define B_SKETCH_BANS GEN_LATEST // In Gen9+, Sketch is unable to copy more moves than in previous generations.
|
||||
#define B_KNOCK_OFF_REMOVAL GEN_LATEST // In Gen5+, Knock Off removes the foe's item instead of rendering it unusable.
|
||||
|
||||
@ -137,6 +137,8 @@ enum FormChanges
|
||||
FORM_CHANGE_OVERWORLD_WEATHER,
|
||||
// Form change that activates when the Pokémon is deposited into the PC or Daycare.
|
||||
FORM_CHANGE_DEPOSIT,
|
||||
// Form change for Minior, which appears unchanged when encountered in the wild
|
||||
FORM_CHANGE_BEGIN_WILD_ENCOUNTER,
|
||||
};
|
||||
|
||||
#endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H
|
||||
|
||||
@ -106,11 +106,16 @@
|
||||
F(B_HEALING_WISH_SWITCH, healingWishSwitch, (u32, GEN_COUNT - 1)) \
|
||||
F(B_DEFOG_EFFECT_CLEARING, defogEffectClearing, (u32, GEN_COUNT - 1)) \
|
||||
F(B_STOCKPILE_RAISES_DEFS, stockpileRaisesDefs, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_TRANSFORM_SEMI_INV_FAIL, transformSemiInvFail, (u32, GEN_COUNT - 1)) \
|
||||
F(B_TRANSFORM_TARGET_FAIL, transformTargetFail, (u32, GEN_COUNT - 1)) \
|
||||
F(B_TRANSFORM_USER_FAIL, transformUserFail, (u32, GEN_COUNT - 1)) \
|
||||
F(B_TRANSFORM_SUBSTITUTE_FAIL, transformSubstituteFail, (u32, GEN_COUNT - 1)) \
|
||||
F(B_TRANSFORM_SHINY, transformShiny, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_TRANSFORM_FORM_CHANGES, transformFormChanges, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_TRANSFORM_FORM_CHANGES, transformFormChanges, (u32, GEN_COUNT - 1)) \
|
||||
F(B_WIDE_GUARD, wideGuard, (u32, GEN_COUNT - 1)) \
|
||||
F(B_QUICK_GUARD, quickGuard, (u32, GEN_COUNT - 1)) \
|
||||
F(B_IMPRISON, imprison, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_TAUNT_ME_FIRST, tauntMeFirst, (u32, GEN_COUNT - 1)) \
|
||||
F(B_ALLY_SWITCH_FAIL_CHANCE, allySwitchFailChance, (u32, GEN_COUNT - 1)) \
|
||||
F(B_SKETCH_BANS, sketchBans, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_KNOCK_OFF_REMOVAL, knockOffRemoval, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
|
||||
@ -43,4 +43,6 @@ void UpdateSparkleFieldEffect(struct Sprite *sprite);
|
||||
void SetSpriteInvisible(u8 spriteId);
|
||||
void ShowWarpArrowSprite(u8 spriteId, u8 direction, s16 x, s16 y);
|
||||
|
||||
u32 FldEff_TallGrass(void);
|
||||
|
||||
#endif //GUARD_FIELD_EFFECT_HELPERS_H
|
||||
|
||||
@ -5694,8 +5694,11 @@ static s32 AI_CalcAdditionalEffectScore(u32 battlerAtk, u32 battlerDef, u32 move
|
||||
u32 i;
|
||||
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
|
||||
|
||||
if (IsSheerForceAffected(move, aiData->abilities[battlerAtk]))
|
||||
if (IsSheerForceAffected(move, aiData->abilities[battlerAtk])
|
||||
&& !(GetMoveEffect(move) == EFFECT_ORDER_UP && gBattleStruct->battlerState[battlerAtk].commanderSpecies != SPECIES_NONE))
|
||||
{
|
||||
return score;
|
||||
}
|
||||
|
||||
// check move additional effects that are likely to happen
|
||||
for (i = 0; i < additionalEffectCount; i++)
|
||||
|
||||
@ -480,7 +480,6 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
u32 incomingMove = GetIncomingMove(battler, opposingBattler, gAiLogicData);
|
||||
enum Type incomingType = CheckDynamicMoveType(GetBattlerMon(opposingBattler), incomingMove, opposingBattler, MON_IN_BATTLE);
|
||||
bool32 isOpposingBattlerChargingOrInvulnerable = !BreaksThroughSemiInvulnerablity(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove);
|
||||
s32 i, j;
|
||||
|
||||
if (!(gAiThinkingStruct->aiFlags[battler] & AI_FLAG_SMART_SWITCHING))
|
||||
@ -530,42 +529,42 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_FLASH_FIRE;
|
||||
}
|
||||
if (incomingType == TYPE_WATER || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_WATER))
|
||||
if (incomingType == TYPE_WATER)
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_WATER_ABSORB;
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_DRY_SKIN;
|
||||
if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_STORM_DRAIN;
|
||||
}
|
||||
if (incomingType == TYPE_ELECTRIC || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_ELECTRIC))
|
||||
if (incomingType == TYPE_ELECTRIC)
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_VOLT_ABSORB;
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_MOTOR_DRIVE;
|
||||
if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_LIGHTNING_ROD;
|
||||
}
|
||||
if (incomingType == TYPE_GRASS || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_GRASS))
|
||||
if (incomingType == TYPE_GRASS)
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_SAP_SIPPER;
|
||||
}
|
||||
if (incomingType == TYPE_GROUND || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_GROUND))
|
||||
if (incomingType == TYPE_GROUND)
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_EARTH_EATER;
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_LEVITATE;
|
||||
}
|
||||
if (IsSoundMove(incomingMove) || (isOpposingBattlerChargingOrInvulnerable && IsSoundMove(incomingMove)))
|
||||
if (IsSoundMove(incomingMove))
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_SOUNDPROOF;
|
||||
}
|
||||
if (IsBallisticMove(incomingMove) || (isOpposingBattlerChargingOrInvulnerable && IsBallisticMove(incomingMove)))
|
||||
if (IsBallisticMove(incomingMove))
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_BULLETPROOF;
|
||||
}
|
||||
if (IsWindMove(incomingMove) || (isOpposingBattlerChargingOrInvulnerable && IsWindMove(incomingMove)))
|
||||
if (IsWindMove(incomingMove))
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_WIND_RIDER;
|
||||
}
|
||||
if (IsPowderMove(incomingMove) || (isOpposingBattlerChargingOrInvulnerable && IsPowderMove(incomingMove)))
|
||||
if (IsPowderMove(incomingMove))
|
||||
{
|
||||
if (GetConfig(B_POWDER_OVERCOAT) >= GEN_6)
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_OVERCOAT;
|
||||
@ -617,14 +616,23 @@ static bool32 ShouldSwitchIfOpponentChargingOrInvulnerable(u32 battler)
|
||||
{
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
u32 incomingMove = GetIncomingMove(battler, opposingBattler, gAiLogicData);
|
||||
|
||||
bool32 isOpposingBattlerChargingOrInvulnerable = !BreaksThroughSemiInvulnerablity(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove);
|
||||
enum BattleMoveEffects effect = GetMoveEffect(incomingMove);
|
||||
|
||||
if (IsDoubleBattle() || !(gAiThinkingStruct->aiFlags[battler] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
// Two-turn attacks that charge without entering semi-invulnerable state (e.g. Solar Beam).
|
||||
// First turn of Fly/Dive/Bounce/Sky Drop: move is selected this turn but user is not yet semi-invulnerable.
|
||||
// Opponent is already semi-invulnerable.
|
||||
if (!(IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove)
|
||||
|| ((effect == EFFECT_SEMI_INVULNERABLE || effect == EFFECT_SKY_DROP) && !IsSemiInvulnerable(opposingBattler, CHECK_ALL))
|
||||
|| IsSemiInvulnerable(opposingBattler, CHECK_ALL)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// In a world with a unified ShouldSwitch function, also want to check whether we already win 1v1 and if we do don't switch; not worth doubling the HasBadOdds computation for now
|
||||
if (isOpposingBattlerChargingOrInvulnerable && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN)))
|
||||
if (gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN)))
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
|
||||
return FALSE;
|
||||
@ -654,7 +662,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler)
|
||||
for (i = firstId; i < lastId; i++)
|
||||
{
|
||||
if (IsAceMon(battler, i))
|
||||
return FALSE;
|
||||
continue;
|
||||
|
||||
monAbility = GetMonAbility(&party[i]);
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ static bool32 AI_IsDoubleSpreadMove(u32 battlerAtk, u32 move)
|
||||
if (moveTargetType == MOVE_TARGET_BOTH && battlerAtk == BATTLE_PARTNER(battlerDef))
|
||||
continue;
|
||||
|
||||
if (IsBattlerAlive(battlerDef) && !IsSemiInvulnerable(battlerDef, move))
|
||||
if (IsBattlerAlive(battlerDef) && (!IsSemiInvulnerable(battlerDef, CHECK_ALL) || BreaksThroughSemiInvulnerablity(battlerDef, move)))
|
||||
numOfTargets++;
|
||||
}
|
||||
|
||||
@ -1034,8 +1034,11 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
|
||||
enum Ability abilityDef = gAiLogicData->abilities[battlerDef];
|
||||
enum Ability abilityAtk = gAiLogicData->abilities[battlerAtk];
|
||||
|
||||
if (IsSheerForceAffected(move, abilityAtk))
|
||||
if (IsSheerForceAffected(move, abilityAtk)
|
||||
&& !(GetMoveEffect(move) == EFFECT_ORDER_UP && gBattleStruct->battlerState[battlerAtk].commanderSpecies != SPECIES_NONE))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
|
||||
@ -206,13 +206,7 @@ static void PlayerPartnerHandleDrawTrainerPic(u32 battler)
|
||||
|
||||
enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId);
|
||||
|
||||
if (IsMultibattleTest())
|
||||
{
|
||||
trainerPicId = TRAINER_BACK_PIC_STEVEN;
|
||||
xPos = 90;
|
||||
yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80;
|
||||
}
|
||||
else if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
{
|
||||
trainerPicId = gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerBackPic;
|
||||
xPos = 90;
|
||||
|
||||
@ -203,11 +203,32 @@ static void RecordedPartnerHandleDrawTrainerPic(u32 battler)
|
||||
s16 xPos, yPos;
|
||||
u32 trainerPicId;
|
||||
|
||||
trainerPicId = TRAINER_BACK_PIC_STEVEN;
|
||||
xPos = 90;
|
||||
yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80;
|
||||
enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId);
|
||||
|
||||
isFrontPic = FALSE;
|
||||
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
{
|
||||
trainerPicId = gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerBackPic;
|
||||
xPos = 90;
|
||||
yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80;
|
||||
}
|
||||
else if (IsAiVsAiBattle())
|
||||
{
|
||||
trainerPicId = GetTrainerPicFromId(gPartnerTrainerId);
|
||||
xPos = 60;
|
||||
yPos = 80;
|
||||
}
|
||||
else
|
||||
{
|
||||
trainerPicId = GetFrontierTrainerFrontSpriteId(gPartnerTrainerId);
|
||||
xPos = 32;
|
||||
yPos = 80;
|
||||
}
|
||||
|
||||
// Use back pic only if the partner Steven or is custom.
|
||||
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
isFrontPic = FALSE;
|
||||
else
|
||||
isFrontPic = TRUE;
|
||||
|
||||
BtlController_HandleDrawTrainerPic(battler, trainerPicId, isFrontPic, xPos, yPos, -1);
|
||||
}
|
||||
@ -246,9 +267,9 @@ static void RecordedPartnerHandleIntroTrainerBallThrow(u32 battler)
|
||||
enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId);
|
||||
|
||||
if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
trainerPal = gTrainerBacksprites[gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic].palette.data;
|
||||
trainerPal = gTrainerBacksprites[gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerBackPic].palette.data;
|
||||
else if (IsAiVsAiBattle())
|
||||
trainerPal = gTrainerSprites[GetTrainerPicFromId(gPartnerTrainerId)].palette.data;
|
||||
trainerPal = gTrainerSprites[GetTrainerBackPicFromId(gPartnerTrainerId)].palette.data;
|
||||
else
|
||||
trainerPal = gTrainerSprites[GetFrontierTrainerFrontSpriteId(gPartnerTrainerId)].palette.data; // 2 vs 2 multi battle in Battle Frontier, load front sprite and pal.
|
||||
|
||||
|
||||
@ -2397,8 +2397,7 @@ void BtlController_HandleDrawTrainerPic(u32 battler, u32 trainerPicId, bool32 is
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) && GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT)
|
||||
gBattlerSpriteIds[battler] = gBattleStruct->trainerSlideSpriteIds[battler];
|
||||
|
||||
// Aiming for palette slots 8 and 9 for Player and PlayerPartner to prevent Trainer Slides causing mons to change colour
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = (8 + battler/2);
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = battler;
|
||||
}
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].x2 = DISPLAY_WIDTH;
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].sSpeedX = -2;
|
||||
@ -2423,8 +2422,7 @@ void BtlController_HandleTrainerSlide(u32 battler, u32 trainerPicId)
|
||||
30);
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) && GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT)
|
||||
gBattlerSpriteIds[battler] = gBattleStruct->trainerSlideSpriteIds[battler];
|
||||
// Aiming for palette slots 8 and 9 for Player and PlayerPartner to prevent Trainer Slides causing mons to change colour
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = (8 + battler/2);
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = battler;
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].x2 = -96;
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].sSpeedX = 2;
|
||||
}
|
||||
@ -2772,7 +2770,7 @@ void BtlController_HandleIntroTrainerBallThrow(u32 battler, u16 tagTrainerPal, c
|
||||
|
||||
paletteNum = AllocSpritePalette(tagTrainerPal);
|
||||
LoadPalette(trainerPal, OBJ_PLTT_ID(paletteNum), PLTT_SIZE_4BPP);
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = (8 + battler/2);
|
||||
gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = paletteNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -700,9 +700,8 @@ void DecompressTrainerBackPic(u16 backPicId, u8 battler)
|
||||
{
|
||||
u8 position = GetBattlerPosition(battler);
|
||||
CopyTrainerBackspriteFramesToDest(backPicId, gMonSpritesGfxPtr->spritesGfx[position]);
|
||||
// Aiming for palette slots 8 and 9 for Player and PlayerPartner to prevent Trainer Slides causing mons to change colour
|
||||
LoadPalette(gTrainerBacksprites[backPicId].palette.data,
|
||||
OBJ_PLTT_ID(8 + battler/2), PLTT_SIZE_4BPP);
|
||||
OBJ_PLTT_ID(battler), PLTT_SIZE_4BPP);
|
||||
}
|
||||
|
||||
void FreeTrainerFrontPicPalette(u16 frontPicId)
|
||||
|
||||
@ -582,7 +582,11 @@ static void CB2_InitBattleInternal(void)
|
||||
TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_BEGIN_BATTLE);
|
||||
TryFormChange(i, B_SIDE_OPPONENT, FORM_CHANGE_BEGIN_BATTLE);
|
||||
}
|
||||
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
|
||||
{
|
||||
TryFormChange(0, B_SIDE_OPPONENT, FORM_CHANGE_BEGIN_WILD_ENCOUNTER);
|
||||
TryFormChange(1, B_SIDE_OPPONENT, FORM_CHANGE_BEGIN_WILD_ENCOUNTER);// Only tries to change the first two opposing slots, assuming these are the only ones occupied in a wild battle.
|
||||
}
|
||||
if (TESTING)
|
||||
{
|
||||
gPlayerPartyCount = CalculatePartyCount(gPlayerParty);
|
||||
@ -3368,6 +3372,9 @@ const u8* FaintClearSetData(u32 battler)
|
||||
if (gBattleStruct->battlerState[battler].commanderSpecies != SPECIES_NONE)
|
||||
{
|
||||
u32 partner = BATTLE_PARTNER(battler);
|
||||
// Clear commander state immediately so a replacement doesn't inherit it.
|
||||
gBattleStruct->battlerState[battler].commanderSpecies = SPECIES_NONE;
|
||||
gBattleMons[partner].volatiles.semiInvulnerable = STATE_NONE;
|
||||
if (IsBattlerAlive(partner))
|
||||
{
|
||||
BtlController_EmitSpriteInvisibility(partner, B_COMM_TO_CONTROLLER, FALSE);
|
||||
@ -3887,6 +3894,7 @@ static void TryDoEventsBeforeFirstTurn(void)
|
||||
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
|
||||
{
|
||||
u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];
|
||||
gBattlerAttacker = battler;
|
||||
if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsOnSwitchInFirstTurnActivation))
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1136,6 +1136,19 @@ static inline bool32 IsBattlerUsingBeakBlast(u32 battler)
|
||||
return !HasBattlerActedThisTurn(battler);
|
||||
}
|
||||
|
||||
static inline bool32 IsInstructBannedChargingMove(u32 battler)
|
||||
{
|
||||
enum BattleMoveEffects moveEffect;
|
||||
|
||||
if (gChosenActionByBattler[battler] != B_ACTION_USE_MOVE || HasBattlerActedThisTurn(battler))
|
||||
return FALSE;
|
||||
|
||||
moveEffect = GetMoveEffect(gChosenMoveByBattler[battler]);
|
||||
return moveEffect == EFFECT_FOCUS_PUNCH
|
||||
|| moveEffect == EFFECT_BEAK_BLAST
|
||||
|| moveEffect == EFFECT_SHELL_TRAP;
|
||||
}
|
||||
|
||||
static void Cmd_attackcanceler(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
@ -3095,7 +3108,9 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
|
||||
case MOVE_EFFECT_TOXIC:
|
||||
case MOVE_EFFECT_FROSTBITE:
|
||||
if (IsSafeguardProtected(gBattlerAttacker, gEffectBattler, GetBattlerAbility(gBattlerAttacker)) && !primary)
|
||||
{
|
||||
gBattlescriptCurrInstr = battleScript;
|
||||
}
|
||||
else if (CanSetNonVolatileStatus(
|
||||
gBattlerAttacker,
|
||||
gEffectBattler,
|
||||
@ -3103,7 +3118,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
|
||||
battlerAbility,
|
||||
moveEffect,
|
||||
CHECK_TRIGGER))
|
||||
{
|
||||
SetNonVolatileStatus(gEffectBattler, moveEffect, battleScript, TRIGGER_ON_MOVE);
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlescriptCurrInstr = battleScript;
|
||||
}
|
||||
break;
|
||||
case MOVE_EFFECT_CONFUSION:
|
||||
if (!CanBeConfused(gEffectBattler)
|
||||
@ -3493,8 +3514,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
|
||||
}
|
||||
break;
|
||||
case MOVE_EFFECT_THROAT_CHOP:
|
||||
gDisableStructs[gEffectBattler].throatChopTimer = 2;
|
||||
gBattlescriptCurrInstr = battleScript;
|
||||
if (gDisableStructs[gEffectBattler].throatChopTimer == 0)
|
||||
{
|
||||
gDisableStructs[gEffectBattler].throatChopTimer = 2;
|
||||
gBattlescriptCurrInstr = battleScript;
|
||||
}
|
||||
break;
|
||||
case MOVE_EFFECT_INCINERATE:
|
||||
if (((gBattleMons[gEffectBattler].item >= FIRST_BERRY_INDEX && gBattleMons[gEffectBattler].item <= LAST_BERRY_INDEX)
|
||||
@ -4246,7 +4270,8 @@ static void Cmd_seteffectprimary(void)
|
||||
|
||||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler);
|
||||
SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, gBattlescriptCurrInstr, EFFECT_PRIMARY);
|
||||
}
|
||||
|
||||
static void Cmd_seteffectsecondary(void)
|
||||
@ -4255,7 +4280,8 @@ static void Cmd_seteffectsecondary(void)
|
||||
|
||||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler);
|
||||
SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, gBattlescriptCurrInstr, NO_FLAGS);
|
||||
}
|
||||
|
||||
static void Cmd_clearvolatile(void)
|
||||
@ -5512,6 +5538,7 @@ static void PlayAnimation(u32 battler, u8 animId, const u16 *argPtr, const u8 *n
|
||||
|| animId == B_ANIM_FORM_CHANGE
|
||||
|| animId == B_ANIM_SUBSTITUTE_FADE
|
||||
|| animId == B_ANIM_PRIMAL_REVERSION
|
||||
|| animId == B_ANIM_POWER_CONSTRUCT
|
||||
|| animId == B_ANIM_ULTRA_BURST
|
||||
|| animId == B_ANIM_TERA_CHARGE
|
||||
|| animId == B_ANIM_TERA_ACTIVATE)
|
||||
@ -5622,7 +5649,7 @@ static inline bool32 CanEjectButtonTrigger(u32 battlerAtk, u32 battlerDef, enum
|
||||
&& battlerAtk != battlerDef
|
||||
&& IsBattlerTurnDamaged(battlerDef)
|
||||
&& IsBattlerAlive(battlerDef)
|
||||
&& CountUsablePartyMons(battlerDef) > 0
|
||||
&& CanBattlerSwitch(battlerDef)
|
||||
&& !(moveEffect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(battlerAtk)))
|
||||
return TRUE;
|
||||
|
||||
@ -5634,7 +5661,7 @@ static inline bool32 CanEjectPackTrigger(u32 battlerAtk, u32 battlerDef, enum Ba
|
||||
if (gDisableStructs[battlerDef].tryEjectPack
|
||||
&& GetBattlerHoldEffect(battlerDef) == HOLD_EFFECT_EJECT_PACK
|
||||
&& IsBattlerAlive(battlerDef)
|
||||
&& CountUsablePartyMons(battlerDef) > 0
|
||||
&& CanBattlerSwitch(battlerDef)
|
||||
&& !gProtectStructs[battlerDef].disableEjectPack
|
||||
&& !(moveEffect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(battlerAtk))
|
||||
&& !(moveEffect == EFFECT_PARTING_SHOT && CanBattlerSwitch(battlerAtk)))
|
||||
@ -11265,10 +11292,11 @@ static void Cmd_transformdataexecution(void)
|
||||
|
||||
gChosenMove = MOVE_UNAVAILABLE;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
if (gBattleMons[gBattlerTarget].volatiles.transformed
|
||||
|| DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)
|
||||
|| gBattleStruct->illusion[gBattlerTarget].state == ILLUSION_ON
|
||||
|| IsSemiInvulnerable(gBattlerTarget, EXCLUDE_COMMANDER))
|
||||
if ((GetConfig(B_TRANSFORM_SEMI_INV_FAIL) >= GEN_2 && IsSemiInvulnerable(gBattlerTarget, EXCLUDE_COMMANDER))
|
||||
|| (GetConfig(B_TRANSFORM_TARGET_FAIL) >= GEN_2 && gBattleMons[gBattlerTarget].volatiles.transformed)
|
||||
|| (GetConfig(B_TRANSFORM_USER_FAIL) >= GEN_5 && gBattleMons[gBattlerAttacker].volatiles.transformed)
|
||||
|| (GetConfig(B_TRANSFORM_SUBSTITUTE_FAIL) >= GEN_5 && DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))
|
||||
|| gBattleStruct->illusion[gBattlerTarget].state == ILLUSION_ON)
|
||||
{
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_FAILED;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TRANSFORM_FAILED;
|
||||
@ -11282,6 +11310,7 @@ static void Cmd_transformdataexecution(void)
|
||||
gBattleMons[gBattlerAttacker].volatiles.transformed = TRUE;
|
||||
gDisableStructs[gBattlerAttacker].disabledMove = MOVE_NONE;
|
||||
gDisableStructs[gBattlerAttacker].disableTimer = 0;
|
||||
gDisableStructs[gBattlerAttacker].transformedMonSpecies = gBattleMons[gBattlerAttacker].species;
|
||||
gDisableStructs[gBattlerAttacker].transformedMonPersonality = gBattleMons[gBattlerTarget].personality;
|
||||
if (B_TRANSFORM_SHINY >= GEN_4)
|
||||
gDisableStructs[gBattlerAttacker].transformedMonShininess = gBattleMons[gBattlerTarget].isShiny;
|
||||
@ -12119,13 +12148,17 @@ static void Cmd_presentdamagecalculation(void)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_HitFromCritCalc;
|
||||
}
|
||||
else if (gBattlerTarget == BATTLE_PARTNER(gBattlerAttacker) && GetBattlerAbility(gBattlerTarget) == ABILITY_TELEPATHY)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_MoveMissedPause;
|
||||
}
|
||||
else if (gBattleMons[gBattlerTarget].maxHP == gBattleMons[gBattlerTarget].hp)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_AlreadyAtFullHp;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] &= ~MOVE_RESULT_DOESNT_AFFECT_FOE;
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] &= ~(MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE);
|
||||
gBattlescriptCurrInstr = BattleScript_PresentHealTarget;
|
||||
}
|
||||
}
|
||||
@ -16529,6 +16562,12 @@ void BS_JumpIfAbilityCantBeReactivated(void)
|
||||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
u32 ability = gBattleMons[battler].ability;
|
||||
|
||||
if (GetBattlerHoldEffectIgnoreAbility(battler) == HOLD_EFFECT_ABILITY_SHIELD)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->jumpInstr;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ability)
|
||||
{
|
||||
case ABILITY_IMPOSTER:
|
||||
@ -17379,6 +17418,9 @@ void BS_TryInstruct(void)
|
||||
u16 move = gLastPrintedMoves[gBattlerTarget];
|
||||
if (move == MOVE_NONE || move == MOVE_UNAVAILABLE || MoveHasAdditionalEffectSelf(move, MOVE_EFFECT_RECHARGE)
|
||||
|| IsMoveInstructBanned(move)
|
||||
|| IsInstructBannedChargingMove(gBattlerTarget)
|
||||
|| gBattleMons[gBattlerTarget].volatiles.bideTurns != 0
|
||||
|| gBattleMons[gBattlerTarget].volatiles.semiInvulnerable == STATE_SKY_DROP
|
||||
|| gBattleMoveEffects[GetMoveEffect(move)].twoTurnEffect
|
||||
|| (GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX)
|
||||
|| IsZMove(move)
|
||||
|
||||
@ -1321,6 +1321,13 @@ static void CB2_EndTrainerBattle(void)
|
||||
DowngradeBadPoison();
|
||||
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
||||
}
|
||||
else if (DidPlayerForfeitNormalTrainerBattle())
|
||||
{
|
||||
if (FlagGet(B_FLAG_NO_WHITEOUT) || CurrentBattlePyramidLocation() != PYRAMID_LOCATION_NONE || InTrainerHillChallenge())
|
||||
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
||||
else
|
||||
SetMainCallback2(CB2_WhiteOut);
|
||||
}
|
||||
else if (IsPlayerDefeated(gBattleOutcome) == TRUE)
|
||||
{
|
||||
if (CurrentBattlePyramidLocation() != PYRAMID_LOCATION_NONE || InTrainerHillChallenge() || (!NoAliveMonsForPlayer()) || FlagGet(B_FLAG_NO_WHITEOUT))
|
||||
@ -1328,10 +1335,6 @@ static void CB2_EndTrainerBattle(void)
|
||||
else
|
||||
SetMainCallback2(CB2_WhiteOut);
|
||||
}
|
||||
else if (DidPlayerForfeitNormalTrainerBattle())
|
||||
{
|
||||
SetMainCallback2(CB2_WhiteOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
||||
|
||||
@ -163,15 +163,19 @@ uq4_12_t GetTeraMultiplier(struct DamageContext *ctx)
|
||||
else
|
||||
return UQ_4_12(2.0);
|
||||
}
|
||||
// Base or Tera type only.
|
||||
else if ((ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
|
||||
|| (ctx->moveType != teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType)))
|
||||
// Tera type only (Adaptability applies).
|
||||
else if (ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
|
||||
{
|
||||
if (ctx->abilityAtk == ABILITY_ADAPTABILITY)
|
||||
return UQ_4_12(2.0);
|
||||
else
|
||||
return UQ_4_12(1.5);
|
||||
}
|
||||
// Base type only (Adaptability does not apply while Terastallized).
|
||||
else if (ctx->moveType != teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
|
||||
{
|
||||
return UQ_4_12(1.5);
|
||||
}
|
||||
// Neither base or Tera type.
|
||||
else
|
||||
{
|
||||
|
||||
@ -1474,7 +1474,10 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler)
|
||||
}
|
||||
}
|
||||
|
||||
if (GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].tauntTimer != 0 && IsBattleMoveStatus(move))
|
||||
if (GetActiveGimmick(battler) != GIMMICK_Z_MOVE
|
||||
&& gDisableStructs[battler].tauntTimer != 0
|
||||
&& IsBattleMoveStatus(move)
|
||||
&& (GetConfig(B_TAUNT_ME_FIRST) < GEN_5 || moveEffect != EFFECT_ME_FIRST))
|
||||
{
|
||||
if ((GetActiveGimmick(battler) == GIMMICK_DYNAMAX))
|
||||
gCurrentMove = MOVE_MAX_GUARD;
|
||||
@ -1709,7 +1712,10 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check)
|
||||
else if (check & MOVE_LIMITATION_TORMENTED && move == gLastMoves[battler] && gBattleMons[battler].volatiles.torment == TRUE)
|
||||
unusableMoves |= 1u << i;
|
||||
// Taunt
|
||||
else if (check & MOVE_LIMITATION_TAUNT && gDisableStructs[battler].tauntTimer && IsBattleMoveStatus(move))
|
||||
else if (check & MOVE_LIMITATION_TAUNT
|
||||
&& gDisableStructs[battler].tauntTimer
|
||||
&& IsBattleMoveStatus(move)
|
||||
&& (GetConfig(B_TAUNT_ME_FIRST) < GEN_5 || moveEffect != EFFECT_ME_FIRST))
|
||||
unusableMoves |= 1u << i;
|
||||
// Imprison
|
||||
else if (check & MOVE_LIMITATION_IMPRISON && GetImprisonedMovesCount(battler, move))
|
||||
@ -2249,7 +2255,12 @@ static enum MoveCanceler CancelerVolatileBlocked(struct BattleContext *ctx)
|
||||
|
||||
static enum MoveCanceler CancelerTaunted(struct BattleContext *ctx)
|
||||
{
|
||||
if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gDisableStructs[ctx->battlerAtk].tauntTimer && IsBattleMoveStatus(ctx->currentMove))
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(ctx->currentMove);
|
||||
|
||||
if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE
|
||||
&& gDisableStructs[ctx->battlerAtk].tauntTimer
|
||||
&& IsBattleMoveStatus(ctx->currentMove)
|
||||
&& (GetConfig(B_TAUNT_ME_FIRST) < GEN_5 || moveEffect != EFFECT_ME_FIRST))
|
||||
{
|
||||
gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE;
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
@ -5407,7 +5418,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
|
||||
if (IsBattlerAlive(gBattlerTarget)
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget, gLastUsedAbility, GetBattlerAbility(gBattlerTarget))
|
||||
&& !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)
|
||||
&& IsMoveMakingContact(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget) // Need to actually hit the target
|
||||
&& RandomPercentage(RNG_POISON_TOUCH, 30))
|
||||
{
|
||||
@ -8134,8 +8145,13 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx)
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0));
|
||||
break;
|
||||
case HOLD_EFFECT_EVIOLITE:
|
||||
if (CanEvolve(gBattleMons[battlerDef].species))
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
|
||||
{
|
||||
u16 species = gBattleMons[battlerDef].species;
|
||||
if (gBattleMons[battlerDef].volatiles.transformed && gDisableStructs[battlerDef].transformedMonSpecies != SPECIES_NONE)
|
||||
species = gDisableStructs[battlerDef].transformedMonSpecies;
|
||||
if (CanEvolve(species))
|
||||
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_ASSAULT_VEST:
|
||||
if (!usesDefStat)
|
||||
@ -8372,12 +8388,12 @@ static inline uq4_12_t GetDefenderAbilitiesModifier(struct DamageContext *ctx)
|
||||
}
|
||||
break;
|
||||
case ABILITY_FLUFFY:
|
||||
if (ctx->moveType == TYPE_FIRE && !IsMoveMakingContact(ctx->battlerAtk, ctx->battlerDef, ABILITY_NONE, ctx->holdEffectAtk, ctx->move))
|
||||
if (ctx->moveType == TYPE_FIRE && !IsMoveMakingContact(ctx->battlerAtk, ctx->battlerDef, ctx->abilityAtk, ctx->holdEffectAtk, ctx->move))
|
||||
{
|
||||
modifier = UQ_4_12(2.0);
|
||||
recordAbility = TRUE;
|
||||
}
|
||||
if (ctx->moveType != TYPE_FIRE && IsMoveMakingContact(ctx->battlerAtk, ctx->battlerDef, ABILITY_NONE, ctx->holdEffectAtk, ctx->move))
|
||||
if (ctx->moveType != TYPE_FIRE && IsMoveMakingContact(ctx->battlerAtk, ctx->battlerDef, ctx->abilityAtk, ctx->holdEffectAtk, ctx->move))
|
||||
{
|
||||
modifier = UQ_4_12(0.5);
|
||||
recordAbility = TRUE;
|
||||
@ -9342,7 +9358,7 @@ static bool32 CanBattlerFormChange(u32 battler, enum FormChanges method)
|
||||
{
|
||||
// Can't change form if transformed.
|
||||
if (gBattleMons[battler].volatiles.transformed
|
||||
&& B_TRANSFORM_FORM_CHANGES >= GEN_5)
|
||||
&& GetConfig(B_TRANSFORM_FORM_CHANGES) >= GEN_5)
|
||||
return FALSE;
|
||||
|
||||
switch (method)
|
||||
@ -10680,7 +10696,7 @@ bool32 TrySwitchInEjectPack(enum EjectPackTiming timing)
|
||||
if (gDisableStructs[i].tryEjectPack
|
||||
&& GetBattlerHoldEffect(i) == HOLD_EFFECT_EJECT_PACK
|
||||
&& IsBattlerAlive(i)
|
||||
&& CountUsablePartyMons(i) > 0)
|
||||
&& CanBattlerSwitch(i))
|
||||
{
|
||||
ejectPackBattlers |= 1u << i;
|
||||
numEjectPackBattlers++;
|
||||
@ -11204,11 +11220,21 @@ static u32 GetAssistMove(void)
|
||||
u32 move = MOVE_NONE;
|
||||
s32 chooseableMovesNo = 0;
|
||||
struct Pokemon *party;
|
||||
u8 battlerByPartyId[PARTY_SIZE];
|
||||
u16 *validMoves = Alloc(sizeof(u16) * PARTY_SIZE * MAX_MON_MOVES);
|
||||
|
||||
if (validMoves != NULL)
|
||||
{
|
||||
party = GetBattlerParty(gBattlerAttacker);
|
||||
for (u32 i = 0; i < PARTY_SIZE; i++)
|
||||
battlerByPartyId[i] = MAX_BATTLERS_COUNT;
|
||||
for (u32 battler = 0; battler < gBattlersCount; battler++)
|
||||
{
|
||||
if (GetBattlerSide(battler) != GetBattlerSide(gBattlerAttacker))
|
||||
continue;
|
||||
if (gBattlerPartyIndexes[battler] < PARTY_SIZE)
|
||||
battlerByPartyId[gBattlerPartyIndexes[battler]] = battler;
|
||||
}
|
||||
|
||||
for (u32 monId = 0; monId < PARTY_SIZE; monId++)
|
||||
{
|
||||
@ -11221,7 +11247,12 @@ static u32 GetAssistMove(void)
|
||||
|
||||
for (u32 moveId = 0; moveId < MAX_MON_MOVES; moveId++)
|
||||
{
|
||||
u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId);
|
||||
u16 move;
|
||||
|
||||
if (battlerByPartyId[monId] != MAX_BATTLERS_COUNT)
|
||||
move = gBattleMons[battlerByPartyId[monId]].moves[moveId];
|
||||
else
|
||||
move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId);
|
||||
|
||||
if (IsMoveAssistBanned(move))
|
||||
continue;
|
||||
|
||||
@ -436,10 +436,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
.accuracy = B_UPDATED_MOVE_DATA >= GEN_3 ? 100 : 75,
|
||||
#if B_UPDATED_MOVE_DATA >= GEN_4
|
||||
.criticalHitStage = 1,
|
||||
#elif B_UPDATED_MOVE_DATA == GEN_3
|
||||
.criticalHitStage = 0,
|
||||
#else
|
||||
#elif B_UPDATED_MOVE_DATA == GEN_2
|
||||
.criticalHitStage = 2,
|
||||
#else
|
||||
.criticalHitStage = 0,
|
||||
#endif
|
||||
.pp = 10,
|
||||
.target = MOVE_TARGET_BOTH,
|
||||
@ -471,6 +471,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
.priority = 0,
|
||||
.category = DAMAGE_CATEGORY_STATUS,
|
||||
.zMove = { .effect = Z_EFFECT_RESET_STATS },
|
||||
.ignoresProtect = TRUE,
|
||||
.mirrorMoveBanned = TRUE,
|
||||
.danceMove = TRUE,
|
||||
.snatchAffected = TRUE,
|
||||
.contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS,
|
||||
@ -3184,6 +3186,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
.priority = 0,
|
||||
.category = DAMAGE_CATEGORY_STATUS,
|
||||
.zMove = { .effect = Z_EFFECT_ATK_UP_2 },
|
||||
.ignoresProtect = TRUE,
|
||||
.mirrorMoveBanned = TRUE,
|
||||
.mimicBanned = TRUE,
|
||||
.metronomeBanned = B_UPDATED_MOVE_FLAGS >= GEN_4,
|
||||
.copycatBanned = TRUE,
|
||||
@ -4519,7 +4523,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
.priority = 0,
|
||||
.category = DAMAGE_CATEGORY_STATUS,
|
||||
.zMove = { .effect = Z_EFFECT_DEF_UP_1 },
|
||||
.ignoresProtect = (B_UPDATED_MOVE_FLAGS >= GEN_6) || (B_UPDATED_MOVE_FLAGS < GEN_3),
|
||||
.ignoresProtect = B_UPDATED_MOVE_FLAGS < GEN_3,
|
||||
.magicCoatAffected = TRUE,
|
||||
.contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS,
|
||||
.contestCategory = CONTEST_CATEGORY_SMART,
|
||||
@ -4696,7 +4700,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
.priority = 0,
|
||||
.category = DAMAGE_CATEGORY_STATUS,
|
||||
.zMove = { .effect = Z_EFFECT_RECOVER_HP },
|
||||
.ignoresProtect = B_UPDATED_MOVE_FLAGS >= GEN_3,
|
||||
.ignoresProtect = TRUE,
|
||||
.ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_5,
|
||||
.mirrorMoveBanned = TRUE,
|
||||
.contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE,
|
||||
@ -4849,6 +4853,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
.category = DAMAGE_CATEGORY_STATUS,
|
||||
.argument = { .protectMethod = PROTECT_NORMAL },
|
||||
.zMove = { .effect = Z_EFFECT_RESET_STATS },
|
||||
.ignoresProtect = TRUE,
|
||||
.mirrorMoveBanned = TRUE,
|
||||
.metronomeBanned = TRUE,
|
||||
.copycatBanned = TRUE,
|
||||
.assistBanned = TRUE,
|
||||
@ -7065,6 +7071,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
.target = MOVE_TARGET_DEPENDS,
|
||||
.priority = 0,
|
||||
.category = DAMAGE_CATEGORY_STATUS,
|
||||
.ignoresProtect = TRUE,
|
||||
.mirrorMoveBanned = TRUE,
|
||||
.metronomeBanned = B_UPDATED_MOVE_FLAGS >= GEN_5,
|
||||
.copycatBanned = TRUE,
|
||||
.sleepTalkBanned = TRUE,
|
||||
@ -7633,6 +7641,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
|
||||
.priority = 4,
|
||||
.category = DAMAGE_CATEGORY_STATUS,
|
||||
.zMove = { .effect = Z_EFFECT_SPD_UP_2 },
|
||||
.ignoresProtect = TRUE,
|
||||
.mirrorMoveBanned = TRUE,
|
||||
.ignoresSubstitute = TRUE,
|
||||
.forcePressure = TRUE,
|
||||
.metronomeBanned = TRUE,
|
||||
|
||||
@ -1316,10 +1316,10 @@ static const struct FormChange sSilvallyFormChangeTable[] =
|
||||
{FORM_CHANGE_TERMINATOR},
|
||||
};
|
||||
#endif //P_FAMILY_TYPE_NULL
|
||||
|
||||
#if P_FAMILY_MINIOR
|
||||
static const struct FormChange sMiniorRedFormChangeTable[] =
|
||||
{
|
||||
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_RED},
|
||||
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_RED},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_RED, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_RED, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
|
||||
@ -1330,6 +1330,7 @@ static const struct FormChange sMiniorRedFormChangeTable[] =
|
||||
};
|
||||
static const struct FormChange sMiniorBlueFormChangeTable[] =
|
||||
{
|
||||
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_BLUE},
|
||||
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_BLUE},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_BLUE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_BLUE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
|
||||
@ -1340,6 +1341,7 @@ static const struct FormChange sMiniorBlueFormChangeTable[] =
|
||||
};
|
||||
static const struct FormChange sMiniorGreenFormChangeTable[] =
|
||||
{
|
||||
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_GREEN},
|
||||
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_GREEN},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_GREEN, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_GREEN, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
|
||||
@ -1350,6 +1352,7 @@ static const struct FormChange sMiniorGreenFormChangeTable[] =
|
||||
};
|
||||
static const struct FormChange sMiniorIndigoFormChangeTable[] =
|
||||
{
|
||||
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_INDIGO},
|
||||
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_INDIGO},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_INDIGO, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_INDIGO, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
|
||||
@ -1360,6 +1363,7 @@ static const struct FormChange sMiniorIndigoFormChangeTable[] =
|
||||
};
|
||||
static const struct FormChange sMiniorOrangeFormChangeTable[] =
|
||||
{
|
||||
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_ORANGE},
|
||||
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_ORANGE},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_ORANGE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_ORANGE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
|
||||
@ -1370,6 +1374,7 @@ static const struct FormChange sMiniorOrangeFormChangeTable[] =
|
||||
};
|
||||
static const struct FormChange sMiniorVioletFormChangeTable[] =
|
||||
{
|
||||
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_VIOLET},
|
||||
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_VIOLET},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_VIOLET, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_VIOLET, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
|
||||
@ -1379,6 +1384,7 @@ static const struct FormChange sMiniorVioletFormChangeTable[] =
|
||||
{FORM_CHANGE_TERMINATOR},
|
||||
};
|
||||
static const struct FormChange sMiniorYellowFormChangeTable[] = {
|
||||
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_YELLOW},
|
||||
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_YELLOW},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_YELLOW, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
|
||||
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_YELLOW, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
|
||||
|
||||
36
src/debug.c
36
src/debug.c
@ -2425,10 +2425,11 @@ static void DebugAction_Give_Pokemon_SelectShiny(u8 taskId)
|
||||
}
|
||||
}
|
||||
|
||||
static void Debug_Display_Ability(enum Ability abilityId, u32 digit, u8 windowId)//(u32 natureId, u32 digit, u8 windowId)
|
||||
static void Debug_Display_Ability(u32 abilityNum, u32 digit, u8 windowId)//(u32 natureId, u32 digit, u8 windowId)
|
||||
{
|
||||
enum Ability abilityId = GetAbilityBySpecies(sDebugMonData->species, abilityNum);
|
||||
StringCopy(gStringVar2, gText_DigitIndicator[digit]);
|
||||
ConvertIntToDecimalStringN(gStringVar3, abilityId, STR_CONV_MODE_LEADING_ZEROS, 2);
|
||||
ConvertIntToDecimalStringN(gStringVar3, abilityNum, STR_CONV_MODE_LEFT_ALIGN, 2);
|
||||
StringCopyPadded(gStringVar3, gStringVar3, CHAR_SPACE, 15);
|
||||
u8 *end = StringCopy(gStringVar1, gAbilitiesInfo[abilityId].name);
|
||||
WrapFontIdToFit(gStringVar1, end, DEBUG_MENU_FONT, WindowWidthPx(windowId));
|
||||
@ -2464,8 +2465,7 @@ static void DebugAction_Give_Pokemon_SelectNature(u8 taskId)
|
||||
gTasks[taskId].tInput = 0;
|
||||
gTasks[taskId].tDigit = 0;
|
||||
|
||||
enum Ability abilityId = GetAbilityBySpecies(sDebugMonData->species, 0);
|
||||
Debug_Display_Ability(abilityId, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId);
|
||||
Debug_Display_Ability(0, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId);
|
||||
|
||||
gTasks[taskId].func = DebugAction_Give_Pokemon_SelectAbility;
|
||||
}
|
||||
@ -2489,8 +2489,7 @@ static void Debug_Display_TeraType(u32 typeId, u32 digit, u8 windowId)
|
||||
|
||||
static void DebugAction_Give_Pokemon_SelectAbility(u8 taskId)
|
||||
{
|
||||
u8 abilityCount = NUM_ABILITY_SLOTS - 1; //-1 for proper iteration
|
||||
u8 i = 0;
|
||||
s32 abilityNum = -1;
|
||||
|
||||
if (JOY_NEW(DPAD_ANY))
|
||||
{
|
||||
@ -2498,28 +2497,31 @@ static void DebugAction_Give_Pokemon_SelectAbility(u8 taskId)
|
||||
|
||||
if (JOY_NEW(DPAD_UP))
|
||||
{
|
||||
gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit];
|
||||
if (gTasks[taskId].tInput > abilityCount)
|
||||
gTasks[taskId].tInput = abilityCount;
|
||||
abilityNum = gTasks[taskId].tInput + 1;
|
||||
while (GetSpeciesAbility(sDebugMonData->species, abilityNum) == ABILITY_NONE && abilityNum < NUM_ABILITY_SLOTS)
|
||||
{
|
||||
abilityNum++;
|
||||
}
|
||||
}
|
||||
if (JOY_NEW(DPAD_DOWN))
|
||||
{
|
||||
gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit];
|
||||
if (gTasks[taskId].tInput < 0)
|
||||
gTasks[taskId].tInput = 0;
|
||||
abilityNum = gTasks[taskId].tInput - 1;
|
||||
while (GetSpeciesAbility(sDebugMonData->species, abilityNum) == ABILITY_NONE && abilityNum >= 0)
|
||||
{
|
||||
abilityNum--;
|
||||
}
|
||||
}
|
||||
|
||||
while (GetAbilityBySpecies(sDebugMonData->species, gTasks[taskId].tInput - i) == ABILITY_NONE && gTasks[taskId].tInput - i < NUM_ABILITY_SLOTS)
|
||||
if (abilityNum >= 0 && abilityNum < NUM_ABILITY_SLOTS)
|
||||
{
|
||||
i++;
|
||||
gTasks[taskId].tInput = abilityNum;
|
||||
Debug_Display_Ability(abilityNum, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId);
|
||||
}
|
||||
enum Ability abilityId = GetAbilityBySpecies(sDebugMonData->species, gTasks[taskId].tInput - i);
|
||||
Debug_Display_Ability(abilityId, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId);
|
||||
}
|
||||
|
||||
if (JOY_NEW(A_BUTTON))
|
||||
{
|
||||
sDebugMonData->abilityNum = gTasks[taskId].tInput - i;
|
||||
sDebugMonData->abilityNum = gTasks[taskId].tInput;
|
||||
gTasks[taskId].tInput = 0;
|
||||
gTasks[taskId].tDigit = 0;
|
||||
|
||||
|
||||
@ -50,6 +50,9 @@ void FakeRtc_TickTimeForward(void)
|
||||
|
||||
void FakeRtc_AdvanceTimeBy(u32 days, u32 hours, u32 minutes, u32 seconds)
|
||||
{
|
||||
if (!OW_USE_FAKE_RTC)
|
||||
return;
|
||||
|
||||
struct DateTime dateTime;
|
||||
struct SiiRtcInfo *rtc = FakeRtc_GetCurrentTime();
|
||||
|
||||
@ -63,6 +66,9 @@ void FakeRtc_AdvanceTimeBy(u32 days, u32 hours, u32 minutes, u32 seconds)
|
||||
|
||||
void FakeRtc_ForwardTimeTo(u32 hour, u32 minute, u32 second)
|
||||
{
|
||||
if (!OW_USE_FAKE_RTC)
|
||||
return;
|
||||
|
||||
Script_PauseFakeRtc();
|
||||
struct Time diff, target;
|
||||
struct SiiRtcInfo *fakeRtc = FakeRtc_GetCurrentTime();
|
||||
|
||||
@ -803,14 +803,22 @@ void FieldEffectScript_LoadTiles(u8 **script)
|
||||
(*script) += 4;
|
||||
}
|
||||
|
||||
static bool32 ShouldFieldEffectBeFogBlended(u8 *script)
|
||||
{
|
||||
u32 ptr = FieldEffectScript_ReadWord(&script);
|
||||
if (ptr == (u32)FldEff_TallGrass)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void FieldEffectScript_LoadFadedPalette(u8 **script)
|
||||
{
|
||||
struct SpritePalette *palette = (struct SpritePalette *)FieldEffectScript_ReadWord(script);
|
||||
u32 paletteSlot = LoadSpritePalette(palette);
|
||||
(*script) += 4;
|
||||
SetPaletteColorMapType(paletteSlot + 16, T1_READ_8(*script));
|
||||
UpdateSpritePaletteWithWeather(paletteSlot, TRUE);
|
||||
(*script)++;
|
||||
UpdateSpritePaletteWithWeather(paletteSlot, ShouldFieldEffectBeFogBlended(*script));
|
||||
}
|
||||
|
||||
void FieldEffectScript_LoadPalette(u8 **script)
|
||||
|
||||
@ -138,7 +138,7 @@ const struct FrontierBrain gFrontierBrainInfo[NUM_FRONTIER_FACILITIES] =
|
||||
COMPOUND_STRING("我巨蛋超级巨星\n可不是浪得虚名!") //Gold
|
||||
},
|
||||
.battledBit = {1 << 2, 1 << 3},
|
||||
.streakAppearances = {1, 2, 5, 0},
|
||||
.streakAppearances = {4, 9, 5, 0},
|
||||
},
|
||||
[FRONTIER_FACILITY_PALACE] =
|
||||
{
|
||||
|
||||
@ -6970,6 +6970,7 @@ u32 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, enum FormChanges
|
||||
case FORM_CHANGE_DEPOSIT:
|
||||
case FORM_CHANGE_FAINT:
|
||||
case FORM_CHANGE_DAYS_PASSED:
|
||||
case FORM_CHANGE_BEGIN_WILD_ENCOUNTER:
|
||||
targetSpecies = formChanges[i].targetSpecies;
|
||||
break;
|
||||
case FORM_CHANGE_STATUS:
|
||||
|
||||
@ -324,7 +324,7 @@ void CreateBattlerSprite(u32 battler)
|
||||
gBattlerSpriteIds[battler] = CreateSprite(&gMultiuseSpriteTemplate, 0x50,
|
||||
(8 - gTrainerBacksprites[gSaveBlock2Ptr->playerGender].coordinates.size) * 4 + 80,
|
||||
GetBattlerSpriteSubpriority(0));
|
||||
gSprites[gBattlerSpriteIds[battler]].oam.paletteNum = (8 + battler / 2);
|
||||
gSprites[gBattlerSpriteIds[battler]].oam.paletteNum = battler;
|
||||
gSprites[gBattlerSpriteIds[battler]].callback = SpriteCallbackDummy;
|
||||
gSprites[gBattlerSpriteIds[battler]].data[0] = battler;
|
||||
}
|
||||
@ -334,7 +334,7 @@ void CreateBattlerSprite(u32 battler)
|
||||
gBattlerSpriteIds[battler] = CreateSprite(&gMultiuseSpriteTemplate, 0x50,
|
||||
(8 - gTrainerBacksprites[TRAINER_BACK_PIC_WALLY].coordinates.size) * 4 + 80,
|
||||
GetBattlerSpriteSubpriority(0));
|
||||
gSprites[gBattlerSpriteIds[battler]].oam.paletteNum = (8 + battler / 2);
|
||||
gSprites[gBattlerSpriteIds[battler]].oam.paletteNum = battler;
|
||||
gSprites[gBattlerSpriteIds[battler]].callback = SpriteCallbackDummy;
|
||||
gSprites[gBattlerSpriteIds[battler]].data[0] = battler;
|
||||
}
|
||||
|
||||
@ -349,7 +349,8 @@ void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds)
|
||||
gLocalTime.hours = hours;
|
||||
gLocalTime.minutes = minutes;
|
||||
gLocalTime.seconds = seconds;
|
||||
FakeRtc_ManuallySetTime(gLocalTime.days, gLocalTime.hours, gLocalTime.minutes, seconds);
|
||||
if (!OW_USE_FAKE_RTC)
|
||||
FakeRtc_ManuallySetTime(gLocalTime.days, gLocalTime.hours, gLocalTime.minutes, seconds);
|
||||
RtcGetInfo(&sRtc);
|
||||
RtcCalcTimeDifference(&sRtc, &gSaveBlock2Ptr->localTimeOffset, &gLocalTime);
|
||||
}
|
||||
|
||||
@ -3239,6 +3239,9 @@ bool8 ScrCmd_fwdtime(struct ScriptContext *ctx)
|
||||
|
||||
bool8 ScrCmd_fwdweekday(struct ScriptContext *ctx)
|
||||
{
|
||||
if (!OW_USE_FAKE_RTC)
|
||||
return FALSE;
|
||||
|
||||
struct SiiRtcInfo *rtc = FakeRtc_GetCurrentTime();
|
||||
|
||||
u32 weekdayTarget = ScriptReadWord(ctx);
|
||||
|
||||
@ -61,4 +61,39 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing into the same type with Adaptability g
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Adaptability does not affect Stellar-type moves");
|
||||
SINGLE_BATTLE_TEST("(TERA) Adaptability does not increase non-Tera base STAB beyond 1.5x", s16 damage)
|
||||
{
|
||||
u32 move;
|
||||
PARAMETRIZE { move = MOVE_GUST; }
|
||||
PARAMETRIZE { move = MOVE_WATER_GUN; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CRAWDAUNT) { Ability(ABILITY_ADAPTABILITY); TeraType(TYPE_NORMAL); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move, gimmick: GIMMICK_TERA); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
// With Adaptability, non-Tera base type should still be 1.5x STAB (not 2.0x).
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("(TERA) Adaptability does not affect Stellar-type moves", s16 damage)
|
||||
{
|
||||
u32 ability;
|
||||
PARAMETRIZE { ability = ABILITY_HYPER_CUTTER; }
|
||||
PARAMETRIZE { ability = ABILITY_ADAPTABILITY; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CRAWDAUNT) { Ability(ability); TeraType(TYPE_STELLAR); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TERA_BLAST, gimmick: GIMMICK_TERA); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_EQ(results[0].damage, results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,6 +380,7 @@ DOUBLE_BATTLE_TEST("Commander Tatsugiri does not attack if Dondozo faints the sa
|
||||
DOUBLE_BATTLE_TEST("Commander Tatsugiri does not get hit by Dragon Darts when a commanded Dondozo faints")
|
||||
{
|
||||
GIVEN {
|
||||
KNOWN_FAILING;
|
||||
ASSUME(GetMoveEffect(MOVE_DRAGON_DARTS) == EFFECT_DRAGON_DARTS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_DONDOZO) { HP(1); }
|
||||
@ -474,3 +475,35 @@ DOUBLE_BATTLE_TEST("Commander will not activate if partner Dondozo is about to s
|
||||
NOT ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Commander clears when Dondozo is replaced and Tatsugiri can be hit")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_VOLT_SWITCH) == EFFECT_HIT_ESCAPE);
|
||||
PLAYER(SPECIES_DONDOZO) { HP(1); Speed(1); }
|
||||
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); MaxHP(400); HP(400); Speed(2); }
|
||||
PLAYER(SPECIES_SEADRA) { Speed(3); }
|
||||
OPPONENT(SPECIES_VENUSAUR) { Speed(5); }
|
||||
OPPONENT(SPECIES_LUXRAY) { Speed(6); }
|
||||
OPPONENT(SPECIES_BUTTERFREE) { Speed(4); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(opponentLeft, MOVE_SEED_BOMB, target: playerRight);
|
||||
MOVE(opponentRight, MOVE_VOLT_SWITCH, target: playerLeft);
|
||||
SEND_OUT(opponentRight, 2);
|
||||
SEND_OUT(playerLeft, 2);
|
||||
}
|
||||
TURN {
|
||||
MOVE(opponentRight, MOVE_BUG_BUZZ, target: playerRight);
|
||||
}
|
||||
} SCENE {
|
||||
ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
|
||||
MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_VOLT_SWITCH, opponentRight);
|
||||
MESSAGE("Dondozo fainted!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEED_BOMB, opponentLeft);
|
||||
HP_BAR(playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BUG_BUZZ, opponentRight);
|
||||
HP_BAR(playerRight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,8 +163,8 @@ SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail do not block Teatim
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_TEATIME) == EFFECT_TEATIME);
|
||||
ASSUME(GetItemHoldEffect(ITEM_ORAN_BERRY) == HOLD_EFFECT_RESTORE_HP);
|
||||
PLAYER(SPECIES_MURKROW) { Ability(ABILITY_PRANKSTER); Item(ITEM_ORAN_BERRY); HP(1); MaxHP(100); }
|
||||
OPPONENT(species) { Ability(ability); Item(ITEM_ORAN_BERRY); HP(1); MaxHP(100); }
|
||||
PLAYER(SPECIES_MURKROW) { Ability(ABILITY_PRANKSTER); Item(ITEM_ORAN_BERRY); HP(60); MaxHP(100); }
|
||||
OPPONENT(species) { Ability(ability); Item(ITEM_ORAN_BERRY); HP(60); MaxHP(100); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TEATIME); }
|
||||
} SCENE {
|
||||
|
||||
@ -70,6 +70,7 @@ SINGLE_BATTLE_TEST("Fluffy halves damage taken from moves that make direct conta
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; }
|
||||
PARAMETRIZE { ability = ABILITY_FLUFFY; }
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_THUNDER_PUNCH));
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_PROTECTIVE_PADS); }
|
||||
OPPONENT(SPECIES_STUFFUL) { Ability(ability); }
|
||||
} WHEN {
|
||||
@ -88,6 +89,8 @@ SINGLE_BATTLE_TEST("Fluffy does not halve damage taken from moves that make dire
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; }
|
||||
PARAMETRIZE { ability = ABILITY_FLUFFY; }
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_THUNDER_PUNCH));
|
||||
ASSUME(IsPunchingMove(MOVE_THUNDER_PUNCH));
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_PUNCHING_GLOVE); }
|
||||
OPPONENT(SPECIES_STUFFUL) { Ability(ability); }
|
||||
} WHEN {
|
||||
@ -99,3 +102,22 @@ SINGLE_BATTLE_TEST("Fluffy does not halve damage taken from moves that make dire
|
||||
EXPECT_EQ(results[0].damage, results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Fluffy does not halve damage taken from moves that make direct contact but are ignored by Long Reach", s16 damage)
|
||||
{
|
||||
enum Ability ability;
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; }
|
||||
PARAMETRIZE { ability = ABILITY_FLUFFY; }
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_THUNDER_PUNCH));
|
||||
PLAYER(SPECIES_ROWLET) { Ability(ABILITY_LONG_REACH); }
|
||||
OPPONENT(SPECIES_STUFFUL) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THUNDER_PUNCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_PUNCH, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_EQ(results[0].damage, results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,3 +201,30 @@ SINGLE_BATTLE_TEST("Gulp Missile triggered by explosion doesn't freeze the game"
|
||||
TURN { MOVE(opponent, MOVE_SURF); MOVE(player, MOVE_EXPLOSION); }
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("(Gulp Missile) Cramorant in Gorging damages an electric type without paralysing")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CRAMORANT) { HP(120); MaxHP(250); Ability(ABILITY_GULP_MISSILE); }
|
||||
OPPONENT(SPECIES_EELEKTROSS);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SURF); MOVE(opponent, MOVE_SCRATCH); }
|
||||
TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, player);
|
||||
HP_BAR(opponent);
|
||||
ABILITY_POPUP(player, ABILITY_GULP_MISSILE);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
|
||||
HP_BAR(player);
|
||||
ABILITY_POPUP(player, ABILITY_GULP_MISSILE);
|
||||
HP_BAR(opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent);
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
}
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
|
||||
HP_BAR(opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,45 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Hadron Engine (Ability) test titles")
|
||||
SINGLE_BATTLE_TEST("Hadron Engine creates Electric Terrain when entering the battle")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_MIRAIDON) { Ability(ABILITY_HADRON_ENGINE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_HADRON_ENGINE);
|
||||
MESSAGE("An electric current ran across the battlefield!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Hadron Engine boosts the Pokemon's Special Attack on Electric Terrain even if not grounded", s16 damage)
|
||||
{
|
||||
bool32 overrideTerrain, airBalloon;
|
||||
|
||||
PARAMETRIZE { airBalloon = FALSE; overrideTerrain = TRUE; }
|
||||
PARAMETRIZE { airBalloon = FALSE; overrideTerrain = FALSE; }
|
||||
PARAMETRIZE { airBalloon = TRUE; overrideTerrain = TRUE; }
|
||||
PARAMETRIZE { airBalloon = TRUE; overrideTerrain = FALSE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_AIR_BALLOON].holdEffect == HOLD_EFFECT_AIR_BALLOON);
|
||||
ASSUME(GetMoveEffect(MOVE_GRASSY_TERRAIN) == EFFECT_GRASSY_TERRAIN);
|
||||
ASSUME(GetMoveCategory(MOVE_POWER_GEM) == DAMAGE_CATEGORY_SPECIAL);
|
||||
PLAYER(SPECIES_MIRAIDON) { Ability(ABILITY_HADRON_ENGINE); Moves(MOVE_POWER_GEM, MOVE_CELEBRATE); Item(airBalloon ? ITEM_AIR_BALLOON : ITEM_NONE); Speed(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_GRASSY_TERRAIN, MOVE_CELEBRATE); Speed(2); }
|
||||
} WHEN {
|
||||
if (overrideTerrain)
|
||||
TURN { MOVE(opponent, MOVE_GRASSY_TERRAIN); }
|
||||
TURN { MOVE(player, MOVE_POWER_GEM); }
|
||||
} SCENE {
|
||||
if (overrideTerrain)
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GRASSY_TERRAIN, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_POWER_GEM, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.3333), results[1].damage);
|
||||
EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.3333), results[3].damage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Heavy Metal (Ability) test titles")
|
||||
// Tests for Heavy Metal are handled in test/battle/ability/light_metal.c
|
||||
|
||||
@ -1,4 +1,30 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Light Metal (Ability) test titles")
|
||||
SINGLE_BATTLE_TEST("Light Metal and Heavy Metal affect the power of Low Kick", s16 damage)
|
||||
{
|
||||
enum Ability ability;
|
||||
PARAMETRIZE { ability = ABILITY_LIGHT_METAL; } // 10.0 - 24.9 kg (40 power)
|
||||
PARAMETRIZE { ability = ABILITY_STALWART; } // 25.0 - 49.9 kg (60 power)
|
||||
PARAMETRIZE { ability = ABILITY_HEAVY_METAL; } // 50.0 - 99.9 kg (80 power)
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_SOAK) == EFFECT_SOAK);
|
||||
ASSUME(GetMoveArgType(MOVE_SOAK) == TYPE_WATER);
|
||||
ASSUME(GetSpeciesWeight(SPECIES_DURALUDON) == 400);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_DURALUDON) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SOAK); } // To remove super-effectiveness, as it was messing with calculations.
|
||||
TURN { MOVE(player, MOVE_LOW_KICK); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LOW_KICK, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} THEN {
|
||||
// Calc 20 power increase, with the first iteration being 40 power
|
||||
if (i != 0)
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12((i * 0.5) + 1), results[i].damage);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Light Metal and Heavy Metal don't affect Heavy Ball's multiplier")
|
||||
|
||||
@ -310,3 +310,32 @@ SINGLE_BATTLE_TEST("Pickpocket does not prevent King's Rock or Razor Fang flinch
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket activates when user has Protective Pads, but not with Punching Glove or Long Reach")
|
||||
{
|
||||
u32 item, ability;
|
||||
|
||||
PARAMETRIZE { item = ITEM_PROTECTIVE_PADS; ability = ABILITY_OVERGROW; }
|
||||
PARAMETRIZE { item = ITEM_PUNCHING_GLOVE; ability = ABILITY_OVERGROW; }
|
||||
PARAMETRIZE { item = ITEM_NONE; ability = ABILITY_LONG_REACH; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_MACH_PUNCH));
|
||||
ASSUME(IsPunchingMove(MOVE_MACH_PUNCH));
|
||||
ASSUME(GetItemHoldEffect(ITEM_PROTECTIVE_PADS) == HOLD_EFFECT_PROTECTIVE_PADS);
|
||||
ASSUME(GetItemHoldEffect(ITEM_PUNCHING_GLOVE) == HOLD_EFFECT_PUNCHING_GLOVE);
|
||||
ASSUME(GetItemHoldEffect(ITEM_FOCUS_SASH) == HOLD_EFFECT_FOCUS_SASH);
|
||||
PLAYER(SPECIES_DECIDUEYE) { Ability(ability); Item(item); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_FOCUS_SASH); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MACH_PUNCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MACH_PUNCH, player);
|
||||
|
||||
if (item == ITEM_PROTECTIVE_PADS) {
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
} else {
|
||||
NOT ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,3 +75,38 @@ SINGLE_BATTLE_TEST("Poison Touch applies between multi-hit move hits")
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Poison Touch activates when user has Protective Pads, but not with Punching Glove")
|
||||
{
|
||||
u32 item;
|
||||
|
||||
PARAMETRIZE { item = ITEM_PROTECTIVE_PADS; }
|
||||
PARAMETRIZE { item = ITEM_PUNCHING_GLOVE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_MACH_PUNCH));
|
||||
ASSUME(IsPunchingMove(MOVE_MACH_PUNCH));
|
||||
ASSUME(GetItemHoldEffect(ITEM_PROTECTIVE_PADS) == HOLD_EFFECT_PROTECTIVE_PADS);
|
||||
ASSUME(GetItemHoldEffect(ITEM_PUNCHING_GLOVE) == HOLD_EFFECT_PUNCHING_GLOVE);
|
||||
PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); Item(item); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MACH_PUNCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MACH_PUNCH, player);
|
||||
|
||||
if (item != ITEM_PUNCHING_GLOVE) {
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("The opposing Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
} else {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("The opposing Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,3 +75,39 @@ SINGLE_BATTLE_TEST("Shields Down protects Minior Meteor from status conditions")
|
||||
EXPECT(opponent->status1 & STATUS1_BURN);
|
||||
}
|
||||
}
|
||||
|
||||
WILD_BATTLE_TEST("Wild Minior appear in Meteor form without transforming")// To be replaced with WILD_DOUBLE_BATTLE_TEST when that is made possible.
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); }
|
||||
OPPONENT(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); }
|
||||
} WHEN {
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_SHIELDS_DOWN);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player);
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_SHIELDS_DOWN);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent);
|
||||
}
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->species, SPECIES_MINIOR_METEOR);
|
||||
EXPECT_EQ(player->species, SPECIES_MINIOR_METEOR);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trainers' Minior appear in Core form")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET)
|
||||
OPPONENT(SPECIES_MINIOR_METEOR) { Ability(ABILITY_SHIELDS_DOWN); }
|
||||
} WHEN {
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_SHIELDS_DOWN);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->species, SPECIES_MINIOR_METEOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,3 +2,27 @@
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Tough Claws (Ability) test titles")
|
||||
|
||||
SINGLE_BATTLE_TEST("Tough Claws boosts contact moves when user has Protective Pads, but not with Punching Glove", s16 damage)
|
||||
{
|
||||
u32 item;
|
||||
|
||||
PARAMETRIZE { item = ITEM_PROTECTIVE_PADS; }
|
||||
PARAMETRIZE { item = ITEM_PUNCHING_GLOVE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_MACH_PUNCH));
|
||||
ASSUME(IsPunchingMove(MOVE_MACH_PUNCH));
|
||||
ASSUME(GetItemHoldEffect(ITEM_PROTECTIVE_PADS) == HOLD_EFFECT_PROTECTIVE_PADS);
|
||||
ASSUME(GetItemHoldEffect(ITEM_PUNCHING_GLOVE) == HOLD_EFFECT_PUNCHING_GLOVE);
|
||||
PLAYER(SPECIES_BARBARACLE) { Ability(ABILITY_TOUGH_CLAWS); Item(item); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MACH_PUNCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MACH_PUNCH, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[1].damage, UQ_4_12(1.18), results[0].damage); // 1.3 / 1.1 ~= 1.18
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,35 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(MoveMakesContact(MOVE_SCRATCH));
|
||||
ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT);
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Unseen Fist (Ability) test titles")
|
||||
|
||||
SINGLE_BATTLE_TEST("Unseen Fist ignores Protect when user has Protective Pads, but not with Punching Glove", s16 damage)
|
||||
{
|
||||
u32 item;
|
||||
|
||||
PARAMETRIZE { item = ITEM_PROTECTIVE_PADS; }
|
||||
PARAMETRIZE { item = ITEM_PUNCHING_GLOVE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_MACH_PUNCH));
|
||||
ASSUME(IsPunchingMove(MOVE_MACH_PUNCH));
|
||||
ASSUME(GetItemHoldEffect(ITEM_PROTECTIVE_PADS) == HOLD_EFFECT_PROTECTIVE_PADS);
|
||||
ASSUME(GetItemHoldEffect(ITEM_PUNCHING_GLOVE) == HOLD_EFFECT_PUNCHING_GLOVE);
|
||||
PLAYER(SPECIES_URSHIFU) { Ability(ABILITY_UNSEEN_FIST); Item(item); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_MACH_PUNCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent);
|
||||
if (item != ITEM_PUNCHING_GLOVE)
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MACH_PUNCH, player);
|
||||
else
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_MACH_PUNCH, player);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1030,6 +1030,21 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out on turn 1 if it predicts a semi-invulnerable move and it has a good switchin")
|
||||
{
|
||||
PASSES_RANDOMLY(PREDICT_MOVE_CHANCE, 100, RNG_AI_PREDICT_MOVE);
|
||||
PASSES_RANDOMLY(SHOULD_SWITCH_FREE_TURN_PERCENTAGE, 100, RNG_AI_SWITCH_FREE_TURN);
|
||||
GIVEN {
|
||||
ASSUME(GetMoveType(MOVE_DIVE) == TYPE_WATER);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING | AI_FLAG_OMNISCIENT | AI_FLAG_PREDICT_MOVE);
|
||||
PLAYER(SPECIES_LUVDISC) { Level(1); Moves(MOVE_DIVE); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SCRATCH); }
|
||||
OPPONENT(SPECIES_PIKACHU) { Moves(MOVE_THUNDERBOLT); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DIVE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has an absorber but current mon has SE move 33% of the time")
|
||||
{
|
||||
PASSES_RANDOMLY(33, 100, RNG_AI_SWITCH_ABSORBING_STAY_IN);
|
||||
@ -1742,9 +1757,10 @@ AI_DOUBLE_BATTLE_TEST("AI will not choose to switch out Dondozo with Commander T
|
||||
PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_ZIGZAGOON) { Moves (MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_CELEBRATE); MOVE(playerRight, MOVE_PERISH_SONG); }
|
||||
TURN { MOVE(playerLeft, MOVE_CELEBRATE); MOVE(playerRight, MOVE_CELEBRATE); }
|
||||
TURN { SWITCH(playerLeft, 2); SWITCH(playerRight, 3); }
|
||||
TURN { MOVE(playerLeft, MOVE_CELEBRATE); MOVE(playerRight, MOVE_CELEBRATE); EXPECT_MOVE(opponentLeft, MOVE_WATER_GUN); }
|
||||
// Commander Tatsugiri cannot act while swallowed, so skip its turn explicitly.
|
||||
TURN { MOVE(playerLeft, MOVE_CELEBRATE); MOVE(playerRight, MOVE_PERISH_SONG); SKIP_TURN(opponentRight); }
|
||||
TURN { MOVE(playerLeft, MOVE_CELEBRATE); MOVE(playerRight, MOVE_CELEBRATE); SKIP_TURN(opponentRight); }
|
||||
TURN { SWITCH(playerLeft, 2); SWITCH(playerRight, 3); SKIP_TURN(opponentRight); }
|
||||
TURN { MOVE(playerLeft, MOVE_CELEBRATE); MOVE(playerRight, MOVE_CELEBRATE); EXPECT_MOVE(opponentLeft, MOVE_WATER_GUN); SKIP_TURN(opponentRight); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +35,38 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Neutralizing Gas")
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ability Shield prevents Intimidate from reactivating after Neutralizing Gas ends")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(5); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(4); }
|
||||
OPPONENT(SPECIES_KOFFING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); Speed(1); }
|
||||
OPPONENT(SPECIES_GYARADOS) { Ability(ABILITY_INTIMIDATE); Item(ITEM_ABILITY_SHIELD); Speed(3); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_NEUTRALIZING_GAS);
|
||||
MESSAGE("Neutralizing gas filled the area!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
|
||||
MESSAGE("The opposing Gyarados's Ability is protected by the effects of its Ability Shield!");
|
||||
ABILITY_POPUP(opponentRight, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
MESSAGE("The effects of the neutralizing gas wore off!");
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponentRight, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
}
|
||||
MESSAGE("The opposing Koffing fainted!");
|
||||
} THEN {
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ability Shield protects against Mold Breaker (no message)")
|
||||
{
|
||||
u32 item;
|
||||
|
||||
@ -1,4 +1,82 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Eviolite (Hold Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gItemsInfo[ITEM_EVIOLITE].holdEffect == HOLD_EFFECT_EVIOLITE);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Eviolite boosts Defense and Sp. Def for unevolved Pokemon", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
u32 item;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SCRATCH; item = ITEM_EVIOLITE; }
|
||||
PARAMETRIZE { move = MOVE_SCRATCH; item = ITEM_NONE; }
|
||||
PARAMETRIZE { move = MOVE_WATER_GUN; item = ITEM_EVIOLITE; }
|
||||
PARAMETRIZE { move = MOVE_WATER_GUN; item = ITEM_NONE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL);
|
||||
PLAYER(SPECIES_PIKACHU) { Item(item); }
|
||||
OPPONENT(SPECIES_MAGIKARP) { Moves(MOVE_SCRATCH, MOVE_WATER_GUN); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
||||
EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.5), results[3].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Eviolite does not boost Defense or Sp. Def for evolved Pokemon", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
u32 item;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SCRATCH; item = ITEM_EVIOLITE; }
|
||||
PARAMETRIZE { move = MOVE_SCRATCH; item = ITEM_NONE; }
|
||||
PARAMETRIZE { move = MOVE_WATER_GUN; item = ITEM_EVIOLITE; }
|
||||
PARAMETRIZE { move = MOVE_WATER_GUN; item = ITEM_NONE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL);
|
||||
PLAYER(SPECIES_RAICHU) { Item(item); }
|
||||
OPPONENT(SPECIES_MAGIKARP) { Moves(MOVE_SCRATCH, MOVE_WATER_GUN); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.0), results[1].damage);
|
||||
EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.0), results[3].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Eviolite uses original species after Transform", s16 damage)
|
||||
{
|
||||
u32 item;
|
||||
|
||||
PARAMETRIZE { item = ITEM_EVIOLITE; }
|
||||
PARAMETRIZE { item = ITEM_NONE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_TRANSFORM) == EFFECT_TRANSFORM);
|
||||
PLAYER(SPECIES_PIKACHU) { Item(item); Moves(MOVE_TRANSFORM, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_GYARADOS) { Moves(MOVE_SCRATCH, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRANSFORM); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,32 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Float Stone (Hold Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetItemHoldEffect(ITEM_FLOAT_STONE) == HOLD_EFFECT_FLOAT_STONE);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Float Stone halves the holder's weight", s16 damage)
|
||||
{
|
||||
u32 item;
|
||||
PARAMETRIZE { item = ITEM_FLOAT_STONE; } // 10.0 - 24.9 kg (40 power)
|
||||
PARAMETRIZE { item = ITEM_NONE; } // 25.0 - 49.9 kg (60 power)
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_SOAK) == EFFECT_SOAK);
|
||||
ASSUME(GetMoveArgType(MOVE_SOAK) == TYPE_WATER);
|
||||
ASSUME(GetSpeciesWeight(SPECIES_DURALUDON) == 400);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_DURALUDON) { Ability(ABILITY_STALWART); Item(item); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SOAK); } // To remove super-effectiveness, as it was messing with calculations.
|
||||
TURN { MOVE(player, MOVE_LOW_KICK); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LOW_KICK, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Float Stone doesn't affect Heavy Ball's multiplier")
|
||||
|
||||
@ -82,3 +82,16 @@ SINGLE_BATTLE_TEST("Sitrus Berry restores HP immediately after Leech Seed damage
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Healing berry animates on the correct battler at battle start")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); MaxHP(400); Item(ITEM_ORAN_BERRY); }
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,24 +92,24 @@ DOUBLE_BATTLE_TEST("Ally Switch does not redirect the target of Snipe Shot")
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ally Switch does not redirect moves done by Pokémon with Stalwart and Propeller Tail")
|
||||
{
|
||||
u16 species;
|
||||
enum Ability ability;
|
||||
PARAMETRIZE { ability = ABILITY_STALWART; }
|
||||
PARAMETRIZE { ability = ABILITY_PROPELLER_TAIL; }
|
||||
PARAMETRIZE { ability = ABILITY_TELEPATHY; }
|
||||
PARAMETRIZE { species = SPECIES_DURALUDON; ability = ABILITY_STALWART; }
|
||||
PARAMETRIZE { species = SPECIES_ARROKUDA; ability = ABILITY_PROPELLER_TAIL; }
|
||||
PARAMETRIZE { species = SPECIES_RALTS; ability = ABILITY_TELEPATHY; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET); // Wobb is playerLeft, but it'll be Wynaut after Ally Switch
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_KADABRA) { Ability(ability); }
|
||||
OPPONENT(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_ABRA);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_SCRATCH, target:playerRight); } // Kadabra targets playerRight Wynaut.
|
||||
TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_SCRATCH, target:playerRight); } // Opponent targets playerRight Wynaut.
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Ally Switch!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft);
|
||||
MESSAGE("Wobbuffet and Wynaut switched places!");
|
||||
|
||||
MESSAGE("The opposing Kadabra used Scratch!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft);
|
||||
HP_BAR((ability == ABILITY_STALWART || ability == ABILITY_PROPELLER_TAIL) ? playerLeft : playerRight);
|
||||
}
|
||||
@ -218,6 +218,7 @@ DOUBLE_BATTLE_TEST("Ally Switch increases the Protect-like moves counter (Gen9+)
|
||||
DOUBLE_BATTLE_TEST("Ally Switch works if ally used two-turn move like Dig")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_DIG)].twoTurnEffect);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@ -313,9 +314,8 @@ DOUBLE_BATTLE_TEST("Ally switch swaps opposing sky drop targets if partner is be
|
||||
DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_ALLY_SWITCH) == EFFECT_ALLY_SWITCH);
|
||||
PLAYER(SPECIES_HOOPA);
|
||||
PLAYER(SPECIES_ZOROARK);
|
||||
PLAYER(SPECIES_ZOROARK) {Ability(ABILITY_ILLUSION); }
|
||||
PLAYER(SPECIES_MAMOSWINE); // the third member here is required for zoroark
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@ -329,6 +329,7 @@ DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data")
|
||||
DOUBLE_BATTLE_TEST("Ally switch updates last used moves for Mimic")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_MIMIC) == EFFECT_MIMIC);
|
||||
PLAYER(SPECIES_XATU) { Speed(100); }
|
||||
PLAYER(SPECIES_RIOLU) { Speed(150); }
|
||||
OPPONENT(SPECIES_FEAROW) { Speed(20); }
|
||||
@ -348,9 +349,10 @@ DOUBLE_BATTLE_TEST("Ally switch updates last used moves for Mimic")
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ally Switch does not update leech seed battler")
|
||||
DOUBLE_BATTLE_TEST("Ally Switch does not update leech seed position")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_LEECH_SEED) == EFFECT_LEECH_SEED);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_SOLOSIS);
|
||||
OPPONENT(SPECIES_BULBASAUR) { HP(50); MaxHP(100); }
|
||||
@ -379,6 +381,114 @@ DOUBLE_BATTLE_TEST("Ally Switch does not update leech seed battler")
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ally Switch does not update Future Sight target position")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_FUTURE_SIGHT) == EFFECT_FUTURE_SIGHT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_ABRA);
|
||||
OPPONENT(SPECIES_RALTS);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_FUTURE_SIGHT, target: playerLeft); }
|
||||
TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); }
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft);
|
||||
MESSAGE("Wynaut took the Future Sight attack!");
|
||||
HP_BAR(playerLeft);
|
||||
NOT HP_BAR(playerRight);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ally Switch does not update Future Sight target position when attacker side switches")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_FUTURE_SIGHT) == EFFECT_FUTURE_SIGHT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_ABRA);
|
||||
OPPONENT(SPECIES_RALTS);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_FUTURE_SIGHT, target: playerLeft); }
|
||||
TURN { SWITCH(opponentLeft, 2); MOVE(opponentRight, MOVE_ALLY_SWITCH); }
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentRight);
|
||||
MESSAGE("Wobbuffet took the Future Sight attack!");
|
||||
HP_BAR(playerLeft);
|
||||
NOT HP_BAR(playerRight);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ally Switch does not update Wish recovery position")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_WISH) == EFFECT_WISH);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); }
|
||||
PLAYER(SPECIES_WYNAUT) { HP(20); MaxHP(100); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_WISH); }
|
||||
TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_WISH, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft);
|
||||
HP_BAR(playerLeft);
|
||||
NOT HP_BAR(playerRight);
|
||||
} THEN {
|
||||
EXPECT_EQ(playerLeft->hp, 70);
|
||||
EXPECT_EQ(playerRight->hp, 50);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ally Switch does not update Healing Wish/Lunar Dance recovery position")
|
||||
{
|
||||
u16 move = MOVE_NONE;
|
||||
struct BattlePokemon *switchTarget = NULL;
|
||||
|
||||
PARAMETRIZE { move = MOVE_HEALING_WISH; switchTarget = playerLeft; }
|
||||
PARAMETRIZE { move = MOVE_HEALING_WISH; switchTarget = playerRight; }
|
||||
PARAMETRIZE { move = MOVE_LUNAR_DANCE; switchTarget = playerLeft; }
|
||||
PARAMETRIZE { move = MOVE_LUNAR_DANCE; switchTarget = playerRight; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(B_HEALING_WISH_SWITCH, GEN_8);
|
||||
ASSUME(GetMoveEffect(MOVE_HEALING_WISH) == EFFECT_HEALING_WISH);
|
||||
ASSUME(GetMoveEffect(MOVE_LUNAR_DANCE) == EFFECT_LUNAR_DANCE);
|
||||
PLAYER(SPECIES_GARDEVOIR);
|
||||
PLAYER(SPECIES_ABRA);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(100); MaxHP(100); }
|
||||
PLAYER(SPECIES_WYNAUT) { HP(50); MaxHP(80); Status1(STATUS1_PARALYSIS); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, move); SEND_OUT(playerLeft, 2); }
|
||||
TURN { MOVE(playerRight, MOVE_ALLY_SWITCH); }
|
||||
TURN { SWITCH(switchTarget, 3); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
|
||||
if (switchTarget == playerLeft) {
|
||||
HP_BAR(playerLeft, hp: 80);
|
||||
STATUS_ICON(playerLeft, none: TRUE);
|
||||
} else {
|
||||
NOT HP_BAR(playerRight);
|
||||
}
|
||||
} THEN {
|
||||
if (switchTarget == playerLeft) {
|
||||
EXPECT_EQ(playerLeft->hp, 80);
|
||||
EXPECT_EQ(playerLeft->status1, STATUS1_NONE);
|
||||
} else {
|
||||
EXPECT_EQ(playerRight->hp, 50);
|
||||
EXPECT_EQ(playerRight->status1, STATUS1_PARALYSIS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ally Switch updates attract battler")
|
||||
{
|
||||
GIVEN {
|
||||
|
||||
@ -1,6 +1,27 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_AQUA_RING) == EFFECT_AQUA_RING);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Aqua Ring fails if already active")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_AQUA_RING); }
|
||||
TURN { MOVE(player, MOVE_AQUA_RING); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_RING, player);
|
||||
MESSAGE("Wobbuffet surrounded itself with a veil of water!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_RING, player);
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Aqua Ring recovers 1/16th HP at end of turn")
|
||||
{
|
||||
GIVEN {
|
||||
@ -15,9 +36,30 @@ SINGLE_BATTLE_TEST("Aqua Ring recovers 1/16th HP at end of turn")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Aqua Ring restores 30% more HP when holding Big Root")
|
||||
{
|
||||
u32 item;
|
||||
u16 expectedHp;
|
||||
PARAMETRIZE { item = ITEM_NONE; expectedHp = 58; }
|
||||
PARAMETRIZE { item = ITEM_BIG_ROOT; expectedHp = 60; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_BIG_ROOT].holdEffect == HOLD_EFFECT_BIG_ROOT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(128); Item(item); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_AQUA_RING); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_RING, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->hp, expectedHp);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Aqua Ring can be used under Heal Block but will not heal the user")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_HEAL_BLOCK) == EFFECT_HEAL_BLOCK);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(128); Speed(50); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }
|
||||
} WHEN {
|
||||
@ -29,4 +71,21 @@ SINGLE_BATTLE_TEST("Aqua Ring can be used under Heal Block but will not heal the
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Aqua Ring's effect");
|
||||
SINGLE_BATTLE_TEST("Aqua Ring's effect is passed by Baton Pass")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT) { HP(50); MaxHP(128); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_AQUA_RING); }
|
||||
TURN { MOVE(player, MOVE_BATON_PASS); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_RING, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BATON_PASS, player);
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
} THEN {
|
||||
EXPECT(player->hp == 58);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ TO_DO_BATTLE_TEST("Assist can call moves with no PP left");
|
||||
TO_DO_BATTLE_TEST("Assist can call moves from a fainted party member");
|
||||
TO_DO_BATTLE_TEST("Assist can call moves that are blocked to its partners"); // Eg. double battle parter blocked by Disable
|
||||
TO_DO_BATTLE_TEST("Assist can only call the original moves of a Transformed partner (Gen4 only)");
|
||||
TO_DO_BATTLE_TEST("Assist can only call the current moves of a Transformed partner (Gen5+)");
|
||||
TO_DO_BATTLE_TEST("Assist cannot call a Mimicked move (Gen4 only)");
|
||||
TO_DO_BATTLE_TEST("Assist can call a Mimicked move but not the original Mimic (Gen5+)");
|
||||
TO_DO_BATTLE_TEST("Assist can call moves in unhatched Eggs (Gen5 only)");
|
||||
@ -57,3 +56,25 @@ SINGLE_BATTLE_TEST("Assisted move triggers correct weakness berry")
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, player);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Assist can only call the current moves of a Transformed partner (Gen5+)")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_TRANSFORM) == EFFECT_TRANSFORM);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(3); Moves(MOVE_ASSIST); }
|
||||
PLAYER(SPECIES_DITTO) { Speed(4); Moves(MOVE_TRANSFORM); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); Moves(MOVE_SCRATCH); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerRight, MOVE_TRANSFORM, target: opponentLeft);
|
||||
MOVE(playerLeft, MOVE_ASSIST);
|
||||
MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ASSIST, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,45 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Autotomize increases Speed by 2 stages");
|
||||
TO_DO_BATTLE_TEST("Autotomize decreases weight by 100kg (220 lbs.)");
|
||||
TO_DO_BATTLE_TEST("Autotomize can be used multiple times to decrease weight each time");
|
||||
TO_DO_BATTLE_TEST("Autotomize increases Speed by 2 stages")
|
||||
|
||||
SINGLE_BATTLE_TEST("Autotomize decreases weight by 100kg (220 lbs.) each time it's used")
|
||||
{
|
||||
s16 damage[3];
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesWeight(SPECIES_METANG) == 2025);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_METANG);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_LOW_KICK); }
|
||||
TURN { MOVE(opponent, MOVE_AUTOTOMIZE); MOVE(player, MOVE_LOW_KICK); }
|
||||
TURN { MOVE(opponent, MOVE_AUTOTOMIZE); MOVE(player, MOVE_LOW_KICK); }
|
||||
} SCENE {
|
||||
// 200.0 kg or more (120 power)
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LOW_KICK, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[0]);
|
||||
|
||||
// 100.0 - 199.9 kg (100 power)
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AUTOTOMIZE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LOW_KICK, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[1]);
|
||||
|
||||
// 0.1 - 9.9 kg (20 power)
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AUTOTOMIZE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LOW_KICK, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[2]);
|
||||
} THEN {
|
||||
EXPECT_MUL_EQ(damage[2], Q_4_12(6.0), damage[0]);
|
||||
EXPECT_MUL_EQ(damage[2], Q_4_12(5.0), damage[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TO_DO_BATTLE_TEST("Autotomize cannot decrease weight below 0.1kg (0.2 lbs)");
|
||||
TO_DO_BATTLE_TEST("Autotomize's weight reduction cannot be Baton Passed");
|
||||
TO_DO_BATTLE_TEST("Autotomize's weight reduction cannot be removed by Haze");
|
||||
TO_DO_BATTLE_TEST("Autotomize's weight reduction is reset upon form change (Gen6+)");
|
||||
TO_DO_BATTLE_TEST("Autotomize's weight reduction is reset upon switch");
|
||||
TO_DO_BATTLE_TEST("Autotomize's weight reduction is reset upon fainting");
|
||||
TO_DO_BATTLE_TEST("Autotomize doesn't affect Heavy Ball's multiplier")
|
||||
|
||||
@ -144,6 +144,7 @@ SINGLE_BATTLE_TEST("Beak Blast doesn't burn fire types")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_ARCANINE].types[1] == TYPE_FIRE);
|
||||
ASSUME(MoveMakesContact(MOVE_SCRATCH));
|
||||
PLAYER(SPECIES_ARCANINE);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
@ -159,6 +160,7 @@ SINGLE_BATTLE_TEST("Beak Blast doesn't burn after being used")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMovePriority(MOVE_COUNTER) < GetMovePriority(MOVE_BEAK_BLAST));
|
||||
ASSUME(MoveMakesContact(MOVE_COUNTER));
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
@ -169,44 +171,29 @@ SINGLE_BATTLE_TEST("Beak Blast doesn't burn after being used")
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Beak Blast doesn't burn if the target is protected")
|
||||
DOUBLE_BATTLE_TEST("Beak Blast doesn't burn if the target is protected by Mat Block")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SPIKY_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_BANEFUL_BUNKER; }
|
||||
PARAMETRIZE { move = MOVE_BURNING_BULWARK; }
|
||||
PARAMETRIZE { move = MOVE_SILK_TRAP; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(move) == EFFECT_PROTECT);
|
||||
ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT);
|
||||
ASSUME(GetMovePriority(MOVE_BEAK_BLAST) > GetMovePriority(MOVE_TRICK_ROOM));
|
||||
ASSUME(GetMoveEffect(MOVE_MAT_BLOCK) == EFFECT_MAT_BLOCK);
|
||||
ASSUME(GetMoveProtectMethod(MOVE_MAT_BLOCK) == PROTECT_MAT_BLOCK);
|
||||
ASSUME(MoveMakesContact(MOVE_POUND));
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(2); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(5); }
|
||||
OPPONENT(SPECIES_WYNAUT) { Speed(10); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, move); }
|
||||
TURN { MOVE(opponentRight, MOVE_INSTRUCT, target: opponentLeft, WITH_RNG(RNG_PROTECT_FAIL, 0));
|
||||
MOVE(opponentLeft, MOVE_BEAK_BLAST, target: playerLeft);
|
||||
MOVE(playerRight, MOVE_TRICK_ROOM);
|
||||
MOVE(playerLeft, MOVE_POUND, target: opponentLeft); }
|
||||
TURN {
|
||||
MOVE(opponentRight, MOVE_MAT_BLOCK);
|
||||
MOVE(opponentLeft, MOVE_BEAK_BLAST, target: playerLeft);
|
||||
MOVE(playerLeft, MOVE_POUND, target: opponentLeft);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_BEAK_BLAST_SETUP, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponentLeft);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerLeft);
|
||||
if (move == MOVE_SPIKY_SHIELD) {
|
||||
HP_BAR(playerLeft);
|
||||
} else if (move == MOVE_BANEFUL_BUNKER) {
|
||||
STATUS_ICON(playerLeft, STATUS1_POISON);
|
||||
} else if (move == MOVE_BURNING_BULWARK) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAT_BLOCK, opponentRight);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerLeft);
|
||||
STATUS_ICON(playerLeft, STATUS1_BURN);
|
||||
} else if (move == MOVE_SILK_TRAP) {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
}
|
||||
NOT STATUS_ICON(playerLeft, STATUS1_BURN);
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,6 +203,7 @@ DOUBLE_BATTLE_TEST("Beak Blast doesn't burn if the target is protected by Quick
|
||||
ASSUME(GetMoveEffect(MOVE_QUICK_GUARD) == EFFECT_PROTECT);
|
||||
ASSUME(GetMoveProtectMethod(MOVE_QUICK_GUARD) == PROTECT_QUICK_GUARD);
|
||||
ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) > 0);
|
||||
ASSUME(MoveMakesContact(MOVE_QUICK_ATTACK));
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(2); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(5); }
|
||||
|
||||
@ -1,4 +1,130 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Ingrain (Move Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_INGRAIN) == EFFECT_INGRAIN);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ingrain fails if already rooted")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_INGRAIN); }
|
||||
TURN { MOVE(player, MOVE_INGRAIN); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INGRAIN, player);
|
||||
MESSAGE("Wobbuffet planted its roots!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_INGRAIN, player);
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ingrain restores 1/16th HP at the end of turn")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(128); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_INGRAIN); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INGRAIN, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->hp, 58);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ingrain restores 30% more HP when holding Big Root")
|
||||
{
|
||||
u32 item;
|
||||
u16 expectedHp;
|
||||
PARAMETRIZE { item = ITEM_NONE; expectedHp = 58; }
|
||||
PARAMETRIZE { item = ITEM_BIG_ROOT; expectedHp = 60; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_BIG_ROOT].holdEffect == HOLD_EFFECT_BIG_ROOT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(128); Item(item); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_INGRAIN); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INGRAIN, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->hp, expectedHp);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ingrain can be used under Heal Block but will not heal the user")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_HEAL_BLOCK) == EFFECT_HEAL_BLOCK);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(128); Speed(50); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_HEAL_BLOCK); MOVE(player, MOVE_INGRAIN); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INGRAIN, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->hp, 50);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ingrain prevents regular switching out")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_INGRAIN); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INGRAIN, player);
|
||||
} THEN {
|
||||
u32 battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
||||
EXPECT_EQ(CanBattlerEscape(battler), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ingrain does not prevent switching out with Flip Turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_FLIP_TURN) == EFFECT_HIT_ESCAPE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_INGRAIN, MOVE_FLIP_TURN); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_INGRAIN); }
|
||||
TURN { MOVE(player, MOVE_FLIP_TURN); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INGRAIN, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLIP_TURN, player);
|
||||
HP_BAR(opponent);
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ingrain's effect is passed by Baton Pass")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_INGRAIN, MOVE_BATON_PASS); }
|
||||
PLAYER(SPECIES_WYNAUT) { HP(50); MaxHP(128); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_INGRAIN); }
|
||||
TURN { MOVE(player, MOVE_BATON_PASS); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_INGRAIN, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BATON_PASS, player);
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->species, SPECIES_WYNAUT);
|
||||
EXPECT_EQ(player->hp, 58);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Red Card and forced switch moves (Roar/Whirlwind) cannot force out a rooted Pokémon");
|
||||
|
||||
@ -52,6 +52,57 @@ DOUBLE_BATTLE_TEST("Instruct fails if move is banned by Instruct")
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Instruct fails if target is in the middle of Bide");
|
||||
|
||||
DOUBLE_BATTLE_TEST("Instruct fails if target is preparing Focus Punch, Beak Blast or Shell Trap")
|
||||
{
|
||||
u32 move, Anim;
|
||||
PARAMETRIZE { move = MOVE_FOCUS_PUNCH; Anim = B_ANIM_FOCUS_PUNCH_SETUP; }
|
||||
PARAMETRIZE { move = MOVE_BEAK_BLAST; Anim = B_ANIM_BEAK_BLAST_SETUP; }
|
||||
PARAMETRIZE { move = MOVE_SHELL_TRAP; Anim = B_ANIM_SHELL_TRAP_SETUP; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_FOCUS_PUNCH) == EFFECT_FOCUS_PUNCH);
|
||||
ASSUME(GetMoveEffect(MOVE_BEAK_BLAST) == EFFECT_BEAK_BLAST);
|
||||
ASSUME(GetMoveEffect(MOVE_SHELL_TRAP) == EFFECT_SHELL_TRAP);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_INSTRUCT, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(3); Moves(MOVE_POUND, move); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_POUND, target: opponentLeft); }
|
||||
TURN {
|
||||
if (move == MOVE_SHELL_TRAP)
|
||||
MOVE(playerRight, move);
|
||||
else
|
||||
MOVE(playerRight, move, target: opponentLeft);
|
||||
MOVE(playerLeft, MOVE_INSTRUCT, target: playerRight);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, Anim, playerRight);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Instruct fails if target is picked up by Sky Drop even if one of the battlers has No Guard")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_SKY_DROP) == EFFECT_SKY_DROP);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(3); Moves(MOVE_INSTRUCT, MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_MACHAMP) { Speed(2); Ability(ABILITY_NO_GUARD); Moves(MOVE_SCRATCH, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_SKY_DROP, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_CELEBRATE); MOVE(playerRight, MOVE_SCRATCH, target: opponentLeft); }
|
||||
TURN { MOVE(opponentLeft, MOVE_SKY_DROP, target: playerRight); MOVE(playerLeft, MOVE_INSTRUCT, target: playerRight); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, opponentLeft);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Instruct-called move targets the target of the move picked on its last use")
|
||||
{
|
||||
GIVEN {
|
||||
|
||||
@ -1,4 +1,29 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Low Kick (Move Effect) test titles")
|
||||
SINGLE_BATTLE_TEST("Low Kick's damage varies based on the target's weight", s16 damage)
|
||||
{
|
||||
u32 species, weight;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_CUBONE; weight = 65; } // 0.1 - 9.9 kg (20 power)
|
||||
PARAMETRIZE { species = SPECIES_SANDSHREW; weight = 120; } // 10.0 - 24.9 kg (40 power)
|
||||
PARAMETRIZE { species = SPECIES_MAROWAK; weight = 450; } // 25.0 - 49.9 kg (60 power)
|
||||
PARAMETRIZE { species = SPECIES_SANDACONDA; weight = 655; } // 50.0 - 99.9 kg (80 power)
|
||||
PARAMETRIZE { species = SPECIES_DONPHAN; weight = 1200; } // 100.0 - 199.9 kg (100 power)
|
||||
PARAMETRIZE { species = SPECIES_HIPPOWDON; weight = 3000; } // 200.0 kg or more (120 power)
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesWeight(species) == weight);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species) { Defense(170); } // Cubone's Defense, the lowest one in hopes of avoid distorting the results.
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_LOW_KICK); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LOW_KICK, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} THEN {
|
||||
// Since Low Kick increases by 20 each tier, multiply by tier number to compare with the first tier.
|
||||
if (i != 0)
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(i + 1), results[i].damage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +82,37 @@ SINGLE_BATTLE_TEST("Me First can be selected if users holds Assault Vest")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Me First can be selected under Taunt in Gen5+")
|
||||
{
|
||||
u32 gen = 0;
|
||||
|
||||
PARAMETRIZE { gen = GEN_4; }
|
||||
PARAMETRIZE { gen = GEN_5; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(B_TAUNT_ME_FIRST, gen);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(100); Moves(MOVE_ME_FIRST, MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_TAUNT, MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TAUNT); }
|
||||
if (gen >= GEN_5) {
|
||||
TURN { MOVE(player, MOVE_ME_FIRST); MOVE(opponent, MOVE_TACKLE); }
|
||||
} else {
|
||||
TURN {
|
||||
MOVE(player, MOVE_ME_FIRST, allowed: FALSE);
|
||||
MOVE(player, MOVE_TACKLE);
|
||||
MOVE(opponent, MOVE_TACKLE);
|
||||
}
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, opponent);
|
||||
if (gen >= GEN_5)
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ME_FIRST, player);
|
||||
else
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Me First deducts power points from itself, not the copied move")
|
||||
{
|
||||
ASSUME(GetMovePP(MOVE_ME_FIRST) == 20);
|
||||
|
||||
@ -1,4 +1,63 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Present (Move Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_PRESENT) == EFFECT_PRESENT);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Present healing through Wonder Guard is still considered to have affected the target")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_MIRROR_MOVE) == EFFECT_MIRROR_MOVE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_SHEDINJA) { Ability(ABILITY_WONDER_GUARD); HP(1); MaxHP(100); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PRESENT, WITH_RNG(RNG_PRESENT, 254)); }
|
||||
TURN { MOVE(opponent, MOVE_MIRROR_MOVE, WITH_RNG(RNG_PRESENT, 1)); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PRESENT, player);
|
||||
HP_BAR(opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRROR_MOVE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PRESENT, opponent);
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Present healing is blocked by Telepathy on an ally target")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); HP(50); MaxHP(100); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_PRESENT, target: playerRight, WITH_RNG(RNG_PRESENT, 254)); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PRESENT, playerLeft);
|
||||
HP_BAR(playerRight);
|
||||
}
|
||||
} THEN {
|
||||
EXPECT_EQ(playerRight->hp, 50);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Present with Parental Bond hits twice when damaging, but only once when healing")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesAbility(SPECIES_KANGASKHAN_MEGA, 0) == ABILITY_PARENTAL_BOND);
|
||||
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PRESENT, gimmick: GIMMICK_MEGA, WITH_RNG(RNG_PRESENT, 1)); }
|
||||
TURN { MOVE(player, MOVE_PRESENT, WITH_RNG(RNG_PRESENT, 254)); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PRESENT, player);
|
||||
HP_BAR(opponent);
|
||||
HP_BAR(opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PRESENT, player);
|
||||
HP_BAR(opponent);
|
||||
NOT HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,37 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Psyblade (Move Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_PSYBLADE) == EFFECT_PSYBLADE);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Psyblade's power increases by 50% on Electric Terrain even if the user is not grounded", s16 damage)
|
||||
{
|
||||
bool32 terrain, airBalloon;
|
||||
|
||||
PARAMETRIZE { terrain = FALSE; airBalloon = FALSE; }
|
||||
PARAMETRIZE { terrain = TRUE; airBalloon = FALSE; }
|
||||
PARAMETRIZE { terrain = FALSE; airBalloon = TRUE; }
|
||||
PARAMETRIZE { terrain = TRUE; airBalloon = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_AIR_BALLOON].holdEffect == HOLD_EFFECT_AIR_BALLOON);
|
||||
ASSUME(GetMoveEffect(MOVE_ELECTRIC_TERRAIN) == EFFECT_ELECTRIC_TERRAIN);
|
||||
ASSUME(GetMoveEffect(MOVE_PSYBLADE) == EFFECT_PSYBLADE);
|
||||
PLAYER(SPECIES_SLOWKING) { Moves(MOVE_ELECTRIC_TERRAIN, MOVE_PSYBLADE); Item(airBalloon ? ITEM_AIR_BALLOON : ITEM_NONE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
if (terrain)
|
||||
TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); }
|
||||
TURN { MOVE(player, MOVE_PSYBLADE); }
|
||||
} SCENE {
|
||||
if (terrain)
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYBLADE, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
||||
EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.5), results[3].damage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ DOUBLE_BATTLE_TEST("Sky Drop is cancelled if Gravity activated")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sky Drop fails on heavy targets")
|
||||
SINGLE_BATTLE_TEST("Sky Drop fails on targets heavier or equal than 200kg")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_METAGROSS].weight >= 2000);
|
||||
|
||||
@ -21,3 +21,20 @@ SINGLE_BATTLE_TEST("Tickle reduces the target's Attack and Defense by 1 stage ea
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Tickle is blocked by Substitute (Gen4+)")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TICKLE, MOVE_CELEBRATE); Speed(5); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SUBSTITUTE, MOVE_CELEBRATE); Speed(10); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_TICKLE); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TICKLE, player);
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,135 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Transform (Move Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_TRANSFORM) == EFFECT_TRANSFORM);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Transform fails on semi-invulnerable target in Gen2+")
|
||||
{
|
||||
u32 genConfig;
|
||||
bool32 expectFail;
|
||||
|
||||
PARAMETRIZE { genConfig = GEN_1; expectFail = FALSE; }
|
||||
PARAMETRIZE { genConfig = GEN_2; expectFail = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(B_TRANSFORM_SEMI_INV_FAIL, genConfig);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_DIG); }
|
||||
OPPONENT(SPECIES_DITTO) { Speed(10); Moves(MOVE_TRANSFORM); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DIG); MOVE(opponent, MOVE_TRANSFORM); }
|
||||
} SCENE {
|
||||
if (expectFail)
|
||||
MESSAGE("But it failed!");
|
||||
else
|
||||
MESSAGE("The opposing Ditto transformed into Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Transform fails on transformed target in Gen2+")
|
||||
{
|
||||
u32 genConfig;
|
||||
bool32 expectFail;
|
||||
|
||||
PARAMETRIZE { genConfig = GEN_1; expectFail = FALSE; }
|
||||
PARAMETRIZE { genConfig = GEN_2; expectFail = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(B_TRANSFORM_TARGET_FAIL, genConfig);
|
||||
PLAYER(SPECIES_DITTO) { Speed(50); Moves(MOVE_TRANSFORM, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(10); Moves(MOVE_TRANSFORM, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRANSFORM); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TRANSFORM); }
|
||||
} SCENE {
|
||||
MESSAGE("Ditto transformed into Wobbuffet!");
|
||||
if (expectFail)
|
||||
MESSAGE("But it failed!");
|
||||
else
|
||||
MESSAGE("The opposing Wobbuffet transformed into Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Transform fails when the user is already transformed in Gen5+")
|
||||
{
|
||||
u32 genConfig;
|
||||
bool32 expectFail;
|
||||
|
||||
PARAMETRIZE { genConfig = GEN_4; expectFail = FALSE; }
|
||||
PARAMETRIZE { genConfig = GEN_5; expectFail = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(B_TRANSFORM_USER_FAIL, genConfig);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_TRANSFORM, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_DITTO) { Speed(10); Moves(MOVE_TRANSFORM, MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TRANSFORM); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TRANSFORM); }
|
||||
} SCENE {
|
||||
MESSAGE("The opposing Ditto transformed into Wobbuffet!");
|
||||
if (expectFail)
|
||||
MESSAGE("But it failed!");
|
||||
else
|
||||
MESSAGE("The opposing Ditto transformed into Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Transform fails on target behind substitute in Gen5+")
|
||||
{
|
||||
u32 genConfig;
|
||||
bool32 expectFail;
|
||||
|
||||
PARAMETRIZE { genConfig = GEN_4; expectFail = FALSE; }
|
||||
PARAMETRIZE { genConfig = GEN_5; expectFail = TRUE; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(B_TRANSFORM_SUBSTITUTE_FAIL, genConfig);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_SUBSTITUTE); }
|
||||
OPPONENT(SPECIES_DITTO) { Speed(10); Moves(MOVE_TRANSFORM); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SUBSTITUTE); MOVE(opponent, MOVE_TRANSFORM); }
|
||||
} SCENE {
|
||||
if (expectFail)
|
||||
MESSAGE("But it failed!");
|
||||
else
|
||||
MESSAGE("The opposing Ditto transformed into Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Transformed Pokemon cannot change forms in Gen5+")
|
||||
{
|
||||
u32 genConfig;
|
||||
bool32 expectFormChange;
|
||||
|
||||
PARAMETRIZE { genConfig = GEN_4; expectFormChange = TRUE; }
|
||||
PARAMETRIZE { genConfig = GEN_5; expectFormChange = FALSE; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(B_TRANSFORM_FORM_CHANGES, genConfig);
|
||||
PLAYER(SPECIES_AEGISLASH) { Moves(MOVE_TACKLE, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_DITTO) { Moves(MOVE_TACKLE, MOVE_TRANSFORM); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TRANSFORM); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
if (expectFormChange) {
|
||||
ABILITY_POPUP(opponent, ABILITY_STANCE_CHANGE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent);
|
||||
} else {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_STANCE_CHANGE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent);
|
||||
}
|
||||
}
|
||||
} THEN {
|
||||
if (expectFormChange)
|
||||
EXPECT_EQ(opponent->species, SPECIES_AEGISLASH_BLADE);
|
||||
else
|
||||
EXPECT_EQ(opponent->species, SPECIES_AEGISLASH);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("(TERA) Transform does not copy the target's Tera Type, and if the user is Terastallized it keeps its own Tera Type")
|
||||
{
|
||||
@ -42,3 +170,5 @@ SINGLE_BATTLE_TEST("Transform returns the user to normal at the end of the battl
|
||||
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_DITTO);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Transform (Move Effect) test titles")
|
||||
|
||||
@ -1,4 +1,42 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Venom Drench (Move Effect) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_VENOM_DRENCH) == EFFECT_VENOM_DRENCH);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Venom Drench lowers stats of a poisoned target")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_VENOM_DRENCH); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_VENOM_DRENCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_VENOM_DRENCH, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE - 1);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Venom Drench is blocked by Substitute")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_VENOM_DRENCH, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SUBSTITUTE, MOVE_CELEBRATE); Status1(STATUS1_POISON); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_CELEBRATE); }
|
||||
TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_VENOM_DRENCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_VENOM_DRENCH, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,8 +27,9 @@ SINGLE_BATTLE_TEST("Throat Chop prevents the usage of sound moves")
|
||||
SINGLE_BATTLE_TEST("Throat Chop prevents sound base moves for 2 turns")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(IsSoundMove(MOVE_HYPER_VOICE));
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HYPER_VOICE, MOVE_ALLURING_VOICE, MOVE_OVERDRIVE, MOVE_ROUND); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HYPER_VOICE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_HYPER_VOICE); MOVE(player, MOVE_THROAT_CHOP); }
|
||||
TURN { FORCED_MOVE(opponent); }
|
||||
@ -45,3 +46,22 @@ SINGLE_BATTLE_TEST("Throat Chop prevents sound base moves for 2 turns")
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Throat Chop usage when target is already prevented from using sound moves doesn't reset timer")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(IsSoundMove(MOVE_HYPER_VOICE));
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HYPER_VOICE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_HYPER_VOICE); MOVE(player, MOVE_THROAT_CHOP); }
|
||||
TURN { FORCED_MOVE(opponent); MOVE(player, MOVE_THROAT_CHOP); }
|
||||
TURN { MOVE(opponent, MOVE_HYPER_VOICE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THROAT_CHOP, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THROAT_CHOP, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, opponent);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user