Bugfixes batch (#6750)

This commit is contained in:
Alex 2025-05-02 20:14:27 +02:00 committed by GitHub
parent 1f5d949013
commit 9259b7ee69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 228 additions and 29 deletions

View File

@ -8399,7 +8399,7 @@ BattleScript_BattlerAbilityStatRaiseOnSwitchIn::
BattleScript_ScriptingAbilityStatRaise::
copybyte gBattlerAbility, sBATTLER
call BattleScript_AbilityPopUp
copybyte sSAVED_DMG, gBattlerAttacker
saveattacker
copybyte gBattlerAttacker, sBATTLER
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_NOT_PROTECT_AFFECTED | MOVE_EFFECT_CERTAIN, NULL
setgraphicalstatchangevalues
@ -8407,7 +8407,7 @@ BattleScript_ScriptingAbilityStatRaise::
waitanimation
printstring STRINGID_ATTACKERABILITYSTATRAISE
waitmessage B_WAIT_TIME_LONG
copybyte gBattlerAttacker, sSAVED_DMG
restoreattacker
return
BattleScript_WeakArmorActivates::

View File

@ -736,19 +736,19 @@ struct BattleStruct
u8 debugBattler;
u8 magnitudeBasePower;
u8 presentBasePower;
u8 roostTypes[MAX_BATTLERS_COUNT][2];
u8 roostTypes[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES];
u8 savedBattlerTarget[5];
u8 savedBattlerAttacker[5];
u8 savedTargetCount:4;
u8 savedAttackerCount:4;
bool8 ateBoost[MAX_BATTLERS_COUNT];
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES]; // two per battler
struct ZMoveData zmove;
struct DynamaxData dynamax;
struct BattleGimmickData gimmick;
const u8 *trainerSlideMsg;
enum BattleIntroStates introState:8;
u8 ateBerry[2]; // array id determined by side, each party pokemon as bit
u8 ateBerry[NUM_BATTLE_SIDES]; // array id determined by side, each party pokemon as bit
u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages
u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct
u16 tracedAbility[MAX_BATTLERS_COUNT];
@ -804,13 +804,14 @@ struct BattleStruct
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
u8 monCausingSleepClause[NUM_BATTLE_SIDES]; // Stores which pokemon on a given side is causing Sleep Clause to be active as the mon's index in the party
u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
s16 savedcheekPouchDamage; // Cheek Pouch can happen in the middle of an attack execution so we need to store the current dmg
u8 cheekPouchActivated:1;
u8 padding2:3;
u8 pursuitStoredSwitch; // Stored id for the Pursuit target's switch
s32 battlerExpReward;
u16 prevTurnSpecies[MAX_BATTLERS_COUNT]; // Stores species the AI has in play at start of turn
s32 moveDamage[MAX_BATTLERS_COUNT];
s32 critChance[MAX_BATTLERS_COUNT];
s16 moveDamage[MAX_BATTLERS_COUNT];
s16 critChance[MAX_BATTLERS_COUNT];
u16 moveResultFlags[MAX_BATTLERS_COUNT];
u8 missStringId[MAX_BATTLERS_COUNT];
u8 noResultString[MAX_BATTLERS_COUNT];
@ -821,10 +822,10 @@ struct BattleStruct
u8 numSpreadTargets:2;
u8 bypassMoldBreakerChecks:1; // for ABILITYEFFECT_IMMUNITY
u8 noTargetPresent:1;
u8 usedEjectItem;
u8 usedMicleBerry;
struct MessageStatus slideMessageStatus;
u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT];
u8 storeBattlerSpriteId;
u16 opponentMonCanTera:6;
u16 opponentMonCanDynamax:6;
u16 padding:4;

View File

@ -1677,6 +1677,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
if (effect == EFFECT_DRAGON_DARTS
&& !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(battlerDef), gCurrentMove)
&& !recalcDragonDarts // So we don't jump back and forth between targets
&& CanTargetPartner(gBattlerAttacker, battlerDef)
&& !TargetFullyImmuneToCurrMove(gBattlerAttacker, BATTLE_PARTNER(battlerDef)))
@ -6496,8 +6497,7 @@ static void Cmd_moveend(void)
else if (moveRecoil > 0
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
&& IsBattlerAlive(gBattlerAttacker)
&& IsBattlerTurnDamaged(gBattlerTarget)
&& gBattleScripting.savedDmg != 0) // Some checks may be redundant alongside this one
&& IsBattlerTurnDamaged(gBattlerTarget))
{
gBattleStruct->moveDamage[gBattlerAttacker] = max(1, gBattleScripting.savedDmg * max(1, moveRecoil) / 100);
BattleScriptPushCursor();
@ -7006,6 +7006,7 @@ static void Cmd_moveend(void)
else
{
if (moveEffect == EFFECT_DRAGON_DARTS
&& !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(gBattlerTarget), gCurrentMove)
&& !(gBattleStruct->moveResultFlags[BATTLE_PARTNER(gBattlerTarget)] & MOVE_RESULT_MISSED) // didn't miss the other target
&& CanTargetPartner(gBattlerAttacker, gBattlerTarget)
&& !TargetFullyImmuneToCurrMove(gBattlerAttacker, BATTLE_PARTNER(gBattlerTarget)))
@ -7157,6 +7158,10 @@ static void Cmd_moveend(void)
if (!(ejectPackBattlers & 1u << battler))
continue;
// Hit escape moves activate before Eject Pack for user
if (moveEffect == EFFECT_HIT_ESCAPE && gBattlerAttacker == battler)
continue;
gBattleScripting.battler = battler;
gLastUsedItem = gBattleMons[battler].item;
@ -9048,7 +9053,7 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId)
&& !IsBattlerAtMaxHp(battler))
{
gBattleStruct->cheekPouchActivated = TRUE;
gBattleScripting.savedDmg = gBattleStruct->moveDamage[battler];
gBattleStruct->savedcheekPouchDamage = gBattleStruct->moveDamage[battler];
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 3;
if (gBattleStruct->moveDamage[battler] == 0)
gBattleStruct->moveDamage[battler] = 1;
@ -9066,7 +9071,7 @@ static void TryRestoreDamageAfterCheeckPouch(u32 battler)
{
if (gBattleStruct->cheekPouchActivated)
{
gBattleStruct->moveDamage[battler] = gBattleScripting.savedDmg;
gBattleStruct->moveDamage[battler] = gBattleStruct->savedcheekPouchDamage;
gBattleStruct->cheekPouchActivated = FALSE;
}
}
@ -10602,6 +10607,7 @@ static void Cmd_various(void)
if ((battlerAbility == ABILITY_MOXIE
|| battlerAbility == ABILITY_CHILLING_NEIGH
|| battlerAbility == ABILITY_AS_ONE_ICE_RIDER)
&& IsBattlerAlive(battler)
&& HasAttackerFaintedTarget()
&& !NoAliveMonsForEitherParty()
&& CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
@ -10625,6 +10631,7 @@ static void Cmd_various(void)
if ((battlerAbility == ABILITY_GRIM_NEIGH
|| battlerAbility == ABILITY_AS_ONE_SHADOW_RIDER)
&& IsBattlerAlive(battler)
&& HasAttackerFaintedTarget()
&& !NoAliveMonsForEitherParty()
&& CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
@ -10663,7 +10670,8 @@ static void Cmd_various(void)
VARIOUS_ARGS();
i = GetHighestStatId(battler);
if (GetBattlerAbility(battler) == ABILITY_BEAST_BOOST
if (IsBattlerAlive(battler)
&& GetBattlerAbility(battler) == ABILITY_BEAST_BOOST
&& HasAttackerFaintedTarget()
&& !NoAliveMonsForEitherParty()
&& CompareStat(gBattlerAttacker, i, MAX_STAT_STAGE, CMP_LESS_THAN))
@ -10701,6 +10709,7 @@ static void Cmd_various(void)
{
VARIOUS_ARGS();
if (GetMoveEffect(gCurrentMove) == EFFECT_FELL_STINGER
&& IsBattlerAlive(gBattlerAttacker)
&& HasAttackerFaintedTarget()
&& !NoAliveMonsForEitherParty()
&& CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
@ -11122,7 +11131,7 @@ static void Cmd_various(void)
if (cmd->case_ == 0)
{
// Save sprite IDs, because trainer slide in will overwrite gBattlerSpriteIds variable.
gBattleScripting.savedDmg = (gBattlerSpriteIds[battler] & 0xFF) | (gBattlerSpriteIds[BATTLE_PARTNER(battler)] << 8);
gBattleStruct->storeBattlerSpriteId = (gBattlerSpriteIds[battler] & 0xFF) | (gBattlerSpriteIds[BATTLE_PARTNER(battler)] << 8);
}
else if (cmd->case_ == 1)
{
@ -11131,9 +11140,8 @@ static void Cmd_various(void)
}
else
{
gBattlerSpriteIds[BATTLE_PARTNER(battler)] = gBattleScripting.savedDmg >> 8;
gBattlerSpriteIds[battler] = gBattleScripting.savedDmg & 0xFF;
gBattleScripting.savedDmg = 0;
gBattlerSpriteIds[BATTLE_PARTNER(battler)] = gBattleStruct->storeBattlerSpriteId >> 8;
gBattlerSpriteIds[battler] = gBattleStruct->storeBattlerSpriteId & 0xFF;
if (IsBattlerAlive(battler))
{
SetBattlerShadowSpriteCallback(battler, gBattleMons[battler].species);

View File

@ -227,15 +227,28 @@ static bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef, u32 a
return FALSE;
}
static inline bool32 IsDragonDartsSecondHit(u32 effect)
{
if (effect != EFFECT_DRAGON_DARTS)
return FALSE;
if (gMultiHitCounter == 1)
return TRUE;
return FALSE;
}
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move)
{
u32 ability = GetBattlerAbility(battlerAtk);
u32 effect = GetMoveEffect(move);
if (gSideTimers[defSide].followmeTimer == 0
|| !IsBattlerAlive(gSideTimers[defSide].followmeTarget)
|| effect == EFFECT_SNIPE_SHOT || effect == EFFECT_SKY_DROP
|| ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART)
|| (!IsBattlerAlive(gSideTimers[defSide].followmeTarget) && !IsDragonDartsSecondHit(effect))
|| effect == EFFECT_SNIPE_SHOT
|| effect == EFFECT_SKY_DROP
|| ability == ABILITY_PROPELLER_TAIL
|| ability == ABILITY_STALWART)
return FALSE;
if (effect == EFFECT_PURSUIT && IsPursuitTargetSet())
@ -3582,6 +3595,9 @@ static void CancellerWeatherPrimal(u32 *effect)
}
if (*effect == 1)
{
gBattleScripting.moveEffect = 0;
gProtectStructs[gBattlerAttacker].chargingTurn = FALSE;
CancelMultiTurnMoves(gBattlerAttacker);
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_PrimalWeatherBlocksMove;
@ -3696,6 +3712,7 @@ static void CancellerMultihitMoves(u32 *effect)
gMultiHitCounter = GetMoveStrikeCount(gCurrentMove);
if (GetMoveEffect(gCurrentMove) == EFFECT_DRAGON_DARTS
&& !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(gBattlerTarget), gCurrentMove)
&& CanTargetPartner(gBattlerAttacker, gBattlerTarget)
&& TargetFullyImmuneToCurrMove(gBattlerAttacker, gBattlerTarget))
gBattlerTarget = BATTLE_PARTNER(gBattlerTarget);
@ -7355,6 +7372,7 @@ u32 RestoreWhiteHerbStats(u32 battler)
}
if (effect != 0)
{
gLastUsedItem = gBattleMons[battler].item;
gBattleScripting.battler = battler;
gPotentialItemEffectBattler = battler;
}
@ -7679,10 +7697,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
case HOLD_EFFECT_RESTORE_STATS:
effect = RestoreWhiteHerbStats(battler);
if (effect != 0)
{
gBattlerAttacker = battler;
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
}
break;
case HOLD_EFFECT_CONFUSE_SPICY:
if (B_BERRIES_INSTANT >= GEN_4)
@ -7898,10 +7913,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
case HOLD_EFFECT_RESTORE_STATS:
effect = RestoreWhiteHerbStats(battler);
if (effect != 0)
{
gBattlerAttacker = battler;
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
}
break;
case HOLD_EFFECT_BLACK_SLUDGE:
if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON))
@ -8190,7 +8202,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
break;
case HOLD_EFFECT_LIFE_ORB:
if (IsBattlerAlive(gBattlerAttacker)
&& (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveDamage[gBattlerTarget]) // Needs the second check in case of Substitute
&& (IsBattlerTurnDamaged(gBattlerTarget) || !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Needs the second check in case of Substitute
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
@ -8311,7 +8323,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
effect = TrySetEnigmaBerry(battler);
break;
case HOLD_EFFECT_JABOCA_BERRY: // consume and damage attacker if used physical move
if (IsBattlerAlive(battler)
if (IsBattlerAlive(gBattlerAttacker)
&& IsBattlerTurnDamaged(gBattlerTarget)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& IsBattleMovePhysical(gCurrentMove)
@ -8331,7 +8343,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
}
break;
case HOLD_EFFECT_ROWAP_BERRY: // consume and damage attacker if used special move
if (IsBattlerAlive(battler)
if (IsBattlerAlive(gBattlerAttacker)
&& IsBattlerTurnDamaged(gBattlerTarget)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& IsBattleMoveSpecial(gCurrentMove)

View File

@ -36,3 +36,23 @@ SINGLE_BATTLE_TEST("Beast Boost boosts the most proficient stat when knocking ou
}
}
}
SINGLE_BATTLE_TEST("Beast Boost doesn't trigger if user is fainted")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_DESTINY_BOND) == EFFECT_DESTINY_BOND);
ASSUME(GetMovePower(MOVE_SCRATCH) > 0);
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_KARTANA) { Ability(ABILITY_BEAST_BOOST); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_DESTINY_BOND); MOVE(opponent, MOVE_SCRATCH); SEND_OUT(player, 1); SEND_OUT(opponent, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_BEAST_BOOST);
SEND_IN_MESSAGE("Wynaut");
MESSAGE("2 sent out Wobbuffet!");
}
}

View File

@ -65,3 +65,21 @@ SINGLE_BATTLE_TEST("Desolate Land does not block a move if pokemon is asleep and
MESSAGE("The opposing Wobbuffet is fast asleep.");
}
}
SINGLE_BATTLE_TEST("Desolate Land will not create a softlock when move in semi invulnerable position is blocked")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
} WHEN {
TURN { MOVE(player, MOVE_DIVE); }
TURN { SWITCH(opponent, 1); SKIP_TURN(player); }
TURN { MOVE(player, MOVE_CELEBRATE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DIVE, player);
ABILITY_POPUP(opponent, ABILITY_DESOLATE_LAND);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DIVE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player);
}
}

View File

@ -58,3 +58,18 @@ SINGLE_BATTLE_TEST("Jaboca Berry tirggers before Bug Bite can steal it")
NOT MESSAGE("Wynaut stole and ate the opposing Wobbuffet's Jaboca Berry!");
}
}
SINGLE_BATTLE_TEST("Jaboca Berry is triggered even if berry user dies")
{
GIVEN {
ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_JABOCA_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
HP_BAR(player);
MESSAGE("Wobbuffet was hurt by the opposing Wobbuffet's Jaboca Berry!");
}
}

View File

@ -0,0 +1,17 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Life Orb activates if it hits a Substitute")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
HP_BAR(player);
MESSAGE("Wobbuffet was hurt by the Life Orb!");
}
}

View File

@ -217,3 +217,21 @@ SINGLE_BATTLE_TEST("White Herb has correct interactions with Intimidate triggere
}
}
}
DOUBLE_BATTLE_TEST("White Herb is correctly displayed")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT) { Item(ITEM_WHITE_HERB); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(playerRight, MOVE_SUPERPOWER, target: opponentRight); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerRight);
MESSAGE("Wynaut returned its stats to normal using its White Herb!");
} THEN {
EXPECT(playerLeft->item == ITEM_NONE);
EXPECT(playerLeft->statStages[STAT_DEF] = DEFAULT_STAT_STAGE);
}
}

View File

@ -57,3 +57,18 @@ SINGLE_BATTLE_TEST("Rowap Berry is not triggered by a physical move")
}
}
}
SINGLE_BATTLE_TEST("Rowap Berry is triggered even if berry user dies")
{
GIVEN {
ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_ROWAP_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_SWIFT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWIFT, player);
HP_BAR(player);
MESSAGE("Wobbuffet was hurt by the opposing Wobbuffet's Rowap Berry!");
}
}

View File

@ -76,6 +76,7 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if the other one is F
PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; speciesLeft = SPECIES_CLEFAIRY; speciesRight = SPECIES_WOBBUFFET; }
PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; }
PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; }
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY);
PLAYER(SPECIES_WOBBUFFET);
@ -252,3 +253,61 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes right ally twice if one strike misses")
MESSAGE("The Pokémon was hit 2 time(s)!");
}
}
DOUBLE_BATTLE_TEST("Dragon Darts strikes will be both redirected to Follow Me user")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
HP_BAR(opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
HP_BAR(opponentRight);
MESSAGE("The Pokémon was hit 2 time(s)!");
}
}
DOUBLE_BATTLE_TEST("Dragon Darts fails to strike any target if under a fairy type follow me user")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_CLEFAIRY);
} WHEN {
TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); }
} SCENE {
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
MESSAGE("The Pokémon was hit 2 time(s)!");
}
}
}
DOUBLE_BATTLE_TEST("Dragon Darts fails to strike the second target if first target fainted and follow me was active")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
} WHEN {
TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
HP_BAR(opponentRight);
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
MESSAGE("The Pokémon was hit 2 time(s)!");
}
}
}

View File

@ -179,3 +179,19 @@ SINGLE_BATTLE_TEST("Hit Escape: Electric Seed boost is received by the right pok
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
}
}
SINGLE_BATTLE_TEST("Hit Escape: U-turn triggers before Eject Pack")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); };
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_GOODRA_HISUI) { Ability(ABILITY_GOOEY); };
} WHEN {
TURN { MOVE(player, MOVE_U_TURN); SEND_OUT(player, 1); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
HP_BAR(opponent);
SEND_IN_MESSAGE("Wynaut");
}
}