Merge branch '_RHH/master' into _RHH/upcoming

This commit is contained in:
Eduardo Quezada 2024-05-02 14:24:17 -04:00
commit 0c74fd31c3
23 changed files with 434 additions and 75 deletions

1
.gitignore vendored
View file

@ -39,3 +39,4 @@ prefabs.json
*.sym
*.js
src/data/map_group_count.h
tools/trainerproc/trainerproc

View file

@ -6326,6 +6326,21 @@ BattleScript_DmgHazardsOnTargetFainted::
moveendall
goto BattleScript_HandleFaintedMon
BattleScript_DmgHazardsOnBattlerScripting::
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE
healthbarupdate BS_SCRIPTING
datahpupdate BS_SCRIPTING
call BattleScript_PrintHurtByDmgHazards
tryfaintmon BS_SCRIPTING
tryfaintmon_spikes BS_SCRIPTING, BattleScript_DmgHazardsOnBattlerScriptingFainted
return
BattleScript_DmgHazardsOnBattlerScriptingFainted::
setbyte sGIVEEXP_STATE, 0
getexp BS_SCRIPTING
moveendall
goto BattleScript_HandleFaintedMon
BattleScript_DmgHazardsOnFaintedBattler::
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE
healthbarupdate BS_FAINTED
@ -6667,6 +6682,7 @@ BattleScript_DoFutureAttackResult:
checkteamslost BattleScript_FutureAttackEnd
BattleScript_FutureAttackEnd::
moveendcase MOVEEND_RAGE
moveendcase MOVEEND_ABILITIES
moveendfromto MOVEEND_ITEM_EFFECTS_ALL, MOVEEND_UPDATE_LAST_MOVES
setbyte gMoveResultFlags, 0
end2

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 386 B

View file

@ -178,7 +178,6 @@ struct ProtectStruct
u32 flinchImmobility:1;
u32 notFirstStrike:1;
u32 palaceUnableToUseMove:1;
u32 usesBouncedMove:1;
u32 usedHealBlockedMove:1;
u32 usedGravityPreventedMove:1;
u32 powderSelfDmg:1;
@ -771,9 +770,10 @@ struct BattleStruct
u8 quickClawBattlerId;
struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member)
u8 forcedSwitch:4; // For each battler
u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
u8 blunderPolicy:1; // should blunder policy activate
u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
u8 bouncedMoveIsUsed:1;
u8 ballSpriteIds[2]; // item gfx, window gfx
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.

View file

@ -80,6 +80,7 @@ extern const u8 BattleScript_EncoredNoMore[];
extern const u8 BattleScript_DestinyBondTakesLife[];
extern const u8 BattleScript_DmgHazardsOnAttacker[];
extern const u8 BattleScript_DmgHazardsOnTarget[];
extern const u8 BattleScript_DmgHazardsOnBattlerScripting[];
extern const u8 BattleScript_DmgHazardsOnFaintedBattler[];
extern const u8 BattleScript_PerishSongTakesLife[];
extern const u8 BattleScript_PerishSongCountGoesDown[];

View file

@ -326,10 +326,10 @@
#define ABILITY_MYCELIUM_MIGHT 298
#define ABILITY_HOSPITALITY 299
#define ABILITY_MINDS_EYE 300
#define ABILITY_EMBODY_ASPECT_TEAL 301
#define ABILITY_EMBODY_ASPECT_HEARTHFLAME 302
#define ABILITY_EMBODY_ASPECT_WELLSPRING 303
#define ABILITY_EMBODY_ASPECT_CORNERSTONE 304
#define ABILITY_EMBODY_ASPECT_TEAL_MASK 301
#define ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK 302
#define ABILITY_EMBODY_ASPECT_WELLSPRING_MASK 303
#define ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK 304
#define ABILITY_TOXIC_CHAIN 305
#define ABILITY_SUPERSWEET_SYRUP 306
#define ABILITY_TERA_SHIFT 307

View file

@ -1535,7 +1535,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler)
s32 currentHP = startingHP;
// No damage being dealt
if ((damageTaken + statusDamage + recurringDamage < recurringHealing) || damageTaken + statusDamage + recurringDamage == 0)
if ((damageTaken + statusDamage + recurringDamage <= recurringHealing) || damageTaken + statusDamage + recurringDamage == 0)
return startingHP;
// Mon fainted to hazards

View file

@ -366,7 +366,7 @@ static inline s32 LowestRollDmg(s32 dmg)
return dmg;
}
bool32 IsDamageMoveUsable(u32 move, u32 battlerAtk, u32 battlerDef)
bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef)
{
s32 moveType;
struct AiLogicData *aiData = AI_DATA;
@ -438,6 +438,10 @@ bool32 IsDamageMoveUsable(u32 move, u32 battlerAtk, u32 battlerDef)
if (!IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[move].argument))
return TRUE;
break;
case EFFECT_HIT_SET_REMOVE_TERRAIN:
if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY))
return TRUE;
break;
}
return FALSE;
@ -486,7 +490,7 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes
GET_MOVE_TYPE(move, moveType);
if (gMovesInfo[move].power)
isDamageMoveUnusable = IsDamageMoveUsable(move, battlerAtk, battlerDef);
isDamageMoveUnusable = IsDamageMoveUnusable(move, battlerAtk, battlerDef);
effectivenessMultiplier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, aiData->abilities[battlerDef], FALSE);
if (gMovesInfo[move].power && !isDamageMoveUnusable)

View file

@ -3144,6 +3144,7 @@ static void PrintBattlerOnAbilityPopUp(u8 battlerId, u8 spriteId1, u8 spriteId2)
static void PrintAbilityOnAbilityPopUp(u32 ability, u8 spriteId1, u8 spriteId2)
{
ClearAbilityName(spriteId1, spriteId2);
PrintOnAbilityPopUp(gAbilitiesInfo[ability].name,
(void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32) + 256,
(void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32) + 256,
@ -3350,7 +3351,6 @@ void UpdateAbilityPopup(u8 battlerId)
u8 spriteId2 = gBattleStruct->abilityPopUpSpriteIds[battlerId][1];
u16 ability = (gBattleScripting.abilityPopupOverwrite != 0) ? gBattleScripting.abilityPopupOverwrite : gBattleMons[battlerId].ability;
ClearAbilityName(spriteId1, spriteId2);
PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2);
RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32));
}

View file

@ -3618,7 +3618,6 @@ const u8* FaintClearSetData(u32 battler)
gProtectStructs[battler].flinchImmobility = FALSE;
gProtectStructs[battler].notFirstStrike = FALSE;
gProtectStructs[battler].usedHealBlockedMove = FALSE;
gProtectStructs[battler].usesBouncedMove = FALSE;
gProtectStructs[battler].usedGravityPreventedMove = FALSE;
gProtectStructs[battler].usedThroatChopPreventedMove = FALSE;
gProtectStructs[battler].statRaised = FALSE;

View file

@ -1378,9 +1378,9 @@ static void Cmd_attackcanceler(void)
if (gProtectStructs[gBattlerTarget].bounceMove
&& gMovesInfo[gCurrentMove].magicCoatAffected
&& !gProtectStructs[gBattlerAttacker].usesBouncedMove)
&& !gBattleStruct->bouncedMoveIsUsed)
{
gProtectStructs[gBattlerTarget].usesBouncedMove = TRUE;
gBattleStruct->bouncedMoveIsUsed = TRUE;
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
// Edge case for bouncing a powder move against a grass type pokemon.
SetAtkCancellerForCalledMove();
@ -1397,18 +1397,33 @@ static void Cmd_attackcanceler(void)
}
return;
}
else if (GetBattlerAbility(gBattlerTarget) == ABILITY_MAGIC_BOUNCE
&& gMovesInfo[gCurrentMove].magicCoatAffected
&& !gProtectStructs[gBattlerAttacker].usesBouncedMove)
else if (gMovesInfo[gCurrentMove].magicCoatAffected && !gBattleStruct->bouncedMoveIsUsed)
{
gProtectStructs[gBattlerTarget].usesBouncedMove = TRUE;
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
// Edge case for bouncing a powder move against a grass type pokemon.
SetAtkCancellerForCalledMove();
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_MagicCoatBounce;
gBattlerAbility = gBattlerTarget;
return;
u32 battler = gBattlerTarget;
if (GetBattlerAbility(gBattlerTarget) == ABILITY_MAGIC_BOUNCE)
{
battler = gBattlerTarget;
gBattleStruct->bouncedMoveIsUsed = TRUE;
}
else if (IsDoubleBattle()
&& gMovesInfo[gCurrentMove].target == MOVE_TARGET_OPPONENTS_FIELD
&& GetBattlerAbility(BATTLE_PARTNER(gBattlerTarget)) == ABILITY_MAGIC_BOUNCE)
{
gBattlerTarget = battler = BATTLE_PARTNER(gBattlerTarget);
gBattleStruct->bouncedMoveIsUsed = TRUE;
}
if (gBattleStruct->bouncedMoveIsUsed)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
// Edge case for bouncing a powder move against a grass type pokemon.
SetAtkCancellerForCalledMove();
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_MagicCoatBounce;
gBattlerAbility = battler;
return;
}
}
// Z-moves and Max Moves bypass protection, but deal reduced damage (factored in AccumulateOtherModifiers)
@ -4423,7 +4438,15 @@ static void Cmd_getexp(void)
gBattleMoveDamage += GetSoftLevelCapExpValue(gPlayerParty[*expMonId].level, gBattleStruct->expShareExpValue);;
}
ApplyExperienceMultipliers(&gBattleMoveDamage, *expMonId, gBattlerFainted);
if (EXP_CAP_HARD && gBattleMoveDamage != 0)
{
u32 growthRate = gSpeciesInfo[GetMonData(&gPlayerParty[*expMonId], MON_DATA_SPECIES)].growthRate;
if (gExperienceTables[growthRate][GetCurrentLevelCap()] < gExperienceTables[growthRate][GetMonData(&gPlayerParty[*expMonId], MON_DATA_LEVEL)] + gBattleMoveDamage)
gBattleMoveDamage = gExperienceTables[growthRate][GetCurrentLevelCap()];
}
if (!EXP_CAP_HARD || gBattleMoveDamage != 0) // Edge case for hard level caps. Prevents mons from getting 1 exp
ApplyExperienceMultipliers(&gBattleMoveDamage, *expMonId, gBattlerFainted);
if (IsTradedMon(&gPlayerParty[*expMonId]))
{
@ -5930,9 +5953,10 @@ static void Cmd_moveend(void)
return;
}
// Check if the move used was actually a bounced move. If so, we need to go back to the original attacker and make sure, its move hits all 2 or 3 pokemon.
else if (gProtectStructs[gBattlerAttacker].usesBouncedMove)
else if (gBattleStruct->bouncedMoveIsUsed)
{
u8 originalBounceTarget = gBattlerAttacker;
gBattleStruct->bouncedMoveIsUsed = FALSE;
gBattlerAttacker = gBattleStruct->attackerBeforeBounce;
gBattleStruct->targetsDone[gBattlerAttacker] |= gBitTable[originalBounceTarget];
gBattleStruct->targetsDone[originalBounceTarget] = 0;
@ -6058,8 +6082,6 @@ static void Cmd_moveend(void)
for (i = 0; i < gBattlersCount; i++)
{
u32 holdEffect;
if (i == gBattlerAttacker)
continue;
holdEffect = GetBattlerHoldEffect(i, TRUE);
if (holdEffect == HOLD_EFFECT_EJECT_BUTTON)
ejectButtonBattlers |= gBitTable[i];
@ -6075,7 +6097,7 @@ static void Cmd_moveend(void)
{
u32 battler = battlers[i];
if (ejectButtonBattlers & gBitTable[battler])
if (battler != gBattlerAttacker && ejectButtonBattlers & gBitTable[battler])
{
if (TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) // Apparently Sheer Force blocks Eject Button, but not Eject Pack
continue;
@ -6233,7 +6255,7 @@ static void Cmd_moveend(void)
if (!(gBattleStruct->lastMoveFailed & gBitTable[gBattlerAttacker]
|| (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove
&& gProtectStructs[gBattlerAttacker].usesBouncedMove)))
&& gBattleStruct->bouncedMoveIsUsed)))
{ // Dance move succeeds
// Set target for other Dancer mons; set bit so that mon cannot activate Dancer off of its own move
if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove)
@ -6328,7 +6350,6 @@ static void Cmd_moveend(void)
CancelMultiTurnMoves(gBattlerAttacker); // Cancel it
gBattleStruct->targetsDone[gBattlerAttacker] = 0;
gProtectStructs[gBattlerAttacker].usesBouncedMove = FALSE;
gProtectStructs[gBattlerAttacker].targetAffected = FALSE;
gProtectStructs[gBattlerAttacker].shellTrap = FALSE;
gBattleStruct->ateBoost[gBattlerAttacker] = 0;
@ -6345,6 +6366,7 @@ static void Cmd_moveend(void)
gBattleStruct->hitSwitchTargetFailed = FALSE;
gBattleStruct->isAtkCancelerForCalledMove = FALSE;
gBattleStruct->swapDamageCategory = FALSE;
gBattleStruct->bouncedMoveIsUsed = FALSE;
gBattleStruct->enduredDamage = 0;
gBattleStruct->additionalEffectsCounter = 0;
gBattleStruct->poisonPuppeteerConfusion = FALSE;
@ -7062,6 +7084,8 @@ static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId)
gBattlescriptCurrInstr = BattleScript_DmgHazardsOnTarget;
else if (gBattlescriptCurrInstr[1] == BS_ATTACKER)
gBattlescriptCurrInstr = BattleScript_DmgHazardsOnAttacker;
else if (gBattlescriptCurrInstr[1] == BS_SCRIPTING)
gBattlescriptCurrInstr = BattleScript_DmgHazardsOnBattlerScripting;
else
gBattlescriptCurrInstr = BattleScript_DmgHazardsOnFaintedBattler;
}
@ -16035,6 +16059,7 @@ void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBat
value *= sExperienceScalingFactors[(faintedLevel * 2) + 10];
value /= sExperienceScalingFactors[faintedLevel + expGetterLevel + 10];
*expAmount = value + 1;
}
}

View file

@ -3519,10 +3519,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
if (effect != 0)
gBattlescriptCurrInstr = BattleScript_PowderMoveNoEffect;
}
if (gProtectStructs[gBattlerAttacker].usesBouncedMove) // Edge case for bouncing a powder move against a grass type pokemon.
gBattleStruct->atkCancellerTracker = CANCELLER_END;
else
gBattleStruct->atkCancellerTracker++;
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_POWDER_STATUS:
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_POWDER)
@ -4775,7 +4772,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITY_HOSPITALITY:
partner = BATTLE_PARTNER(battler);
if (!gSpecialStatuses[battler].switchInAbilityDone && IsDoubleBattle() && gBattleMons[partner].hp < gBattleMons[partner].maxHP)
if (!gSpecialStatuses[battler].switchInAbilityDone
&& IsDoubleBattle()
&& gBattleMons[partner].hp < gBattleMons[partner].maxHP
&& IsBattlerAlive(partner))
{
gBattlerTarget = partner;
gBattlerAttacker = battler;
@ -4785,22 +4785,22 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
effect++;
}
break;
case ABILITY_EMBODY_ASPECT_TEAL:
case ABILITY_EMBODY_ASPECT_HEARTHFLAME:
case ABILITY_EMBODY_ASPECT_WELLSPRING:
case ABILITY_EMBODY_ASPECT_CORNERSTONE:
case ABILITY_EMBODY_ASPECT_TEAL_MASK:
case ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK:
case ABILITY_EMBODY_ASPECT_WELLSPRING_MASK:
case ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK:
if (!gSpecialStatuses[battler].switchInAbilityDone)
{
u32 stat = STAT_SPATK;
u32 stat;
if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_TEAL)
stat = STAT_SPATK;
else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_HEARTHFLAME)
if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK)
stat = STAT_ATK;
else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_WELLSPRING)
else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_WELLSPRING_MASK)
stat = STAT_SPDEF;
else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_CORNERSTONE)
else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK)
stat = STAT_DEF;
else //ABILITY_EMBODY_ASPECT_TEAL_MASK
stat = STAT_SPEED;
if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_EQUAL))
break;

View file

@ -1276,6 +1276,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
.name = _("Fur Coat"),
.description = COMPOUND_STRING("Raises Defense."),
.aiRating = 7,
.breakable = TRUE,
},
[ABILITY_MAGICIAN] =
@ -2472,7 +2473,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
.breakable = TRUE,
},
[ABILITY_EMBODY_ASPECT_TEAL] =
[ABILITY_EMBODY_ASPECT_TEAL_MASK] =
{
#if B_EXPANDED_ABILITY_NAMES == TRUE
.name = _("Embody Aspect"),
@ -2487,7 +2488,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
.failsOnImposter = TRUE,
},
[ABILITY_EMBODY_ASPECT_HEARTHFLAME] =
[ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK] =
{
#if B_EXPANDED_ABILITY_NAMES == TRUE
.name = _("Embody Aspect"),
@ -2502,7 +2503,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
.failsOnImposter = TRUE,
},
[ABILITY_EMBODY_ASPECT_WELLSPRING] =
[ABILITY_EMBODY_ASPECT_WELLSPRING_MASK] =
{
#if B_EXPANDED_ABILITY_NAMES == TRUE
.name = _("Embody Aspect"),
@ -2517,7 +2518,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
.failsOnImposter = TRUE,
},
[ABILITY_EMBODY_ASPECT_CORNERSTONE] =
[ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK] =
{
#if B_EXPANDED_ABILITY_NAMES == TRUE
.name = _("Embody Aspect"),

View file

@ -6312,10 +6312,10 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
[SPECIES_OGERPON_HEARTHFLAME_MASK] = OGERPON_SPECIES_INFO(HearthflameMask, TYPE_FIRE, ABILITY_MOLD_BREAKER, BODY_COLOR_RED, 0),
[SPECIES_OGERPON_CORNERSTONE_MASK] = OGERPON_SPECIES_INFO(CornerstoneMask, TYPE_ROCK, ABILITY_STURDY, BODY_COLOR_GRAY, 0),
#if P_TERA_FORMS
[SPECIES_OGERPON_TEAL_MASK_TERA] = OGERPON_SPECIES_INFO(TealMask, TYPE_GRASS, ABILITY_EMBODY_ASPECT_TEAL, BODY_COLOR_GREEN, 1),
[SPECIES_OGERPON_WELLSPRING_MASK_TERA] = OGERPON_SPECIES_INFO(WellspringMask, TYPE_WATER, ABILITY_EMBODY_ASPECT_WELLSPRING, BODY_COLOR_BLUE, 0),
[SPECIES_OGERPON_HEARTHFLAME_MASK_TERA] = OGERPON_SPECIES_INFO(HearthflameMask, TYPE_FIRE, ABILITY_EMBODY_ASPECT_HEARTHFLAME, BODY_COLOR_RED, 0),
[SPECIES_OGERPON_CORNERSTONE_MASK_TERA] = OGERPON_SPECIES_INFO(CornerstoneMask, TYPE_ROCK, ABILITY_EMBODY_ASPECT_CORNERSTONE, BODY_COLOR_GRAY, 0),
[SPECIES_OGERPON_TEAL_MASK_TERA] = OGERPON_SPECIES_INFO(TealMask, TYPE_GRASS, ABILITY_EMBODY_ASPECT_TEAL_MASK, BODY_COLOR_GREEN, 1),
[SPECIES_OGERPON_WELLSPRING_MASK_TERA] = OGERPON_SPECIES_INFO(WellspringMask, TYPE_WATER, ABILITY_EMBODY_ASPECT_WELLSPRING_MASK, BODY_COLOR_BLUE, 0),
[SPECIES_OGERPON_HEARTHFLAME_MASK_TERA] = OGERPON_SPECIES_INFO(HearthflameMask, TYPE_FIRE, ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK, BODY_COLOR_RED, 0),
[SPECIES_OGERPON_CORNERSTONE_MASK_TERA] = OGERPON_SPECIES_INFO(CornerstoneMask, TYPE_ROCK, ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK, BODY_COLOR_GRAY, 0),
#endif //P_TERA_FORMS
#endif //P_FAMILY_OGERPON

View file

@ -386,7 +386,7 @@ struct PokemonStats
u8 eggGroup1;
u8 eggGroup2;
u8 eggCycles;
u16 expYield;
u16 expYield;
u8 friendship;
u16 ability0;
u16 ability1;

View file

@ -3534,8 +3534,17 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
{
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
dataUnsigned = sExpCandyExperienceTable[param - 1] + GetMonData(mon, MON_DATA_EXP, NULL);
if (dataUnsigned > gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL])
if (B_RARE_CANDY_CAP && EXP_CAP_HARD)
{
u32 currentLevelCap = GetCurrentLevelCap();
if (dataUnsigned > gExperienceTables[gSpeciesInfo[species].growthRate][currentLevelCap])
dataUnsigned = gExperienceTables[gSpeciesInfo[species].growthRate][currentLevelCap];
}
else if (dataUnsigned > gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL])
{
dataUnsigned = gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL];
}
}
if (dataUnsigned != 0) // Failsafe

View file

@ -0,0 +1,148 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Color Change changes the type of a Pokemon being hit by a move if the type of the move and the Pokemon are different")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("Foe Wobbuffet's Color Change made it the Normal type!");
}
}
SINGLE_BATTLE_TEST("Color Change does not change the type when hit by a move that's the same type as itself")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(player, MOVE_PSYCHO_CUT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHO_CUT, player);
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("Foe Wobbuffet's Color Change made it the Normal type!");
}
}
}
SINGLE_BATTLE_TEST("Color Change does not change the type of a dual-type Pokemon when hit by a move that shares its primary type")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_XATU) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(player, MOVE_PSYCHO_CUT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHO_CUT, player);
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("Foe Xatu's Color Change made it the Psychic type!");
}
}
}
SINGLE_BATTLE_TEST("Color Change does not change the type of a dual-type Pokemon when hit by a move that shares its secondary type")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SLOWBRO) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(player, MOVE_PSYCHO_CUT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHO_CUT, player);
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("Foe Slowbro's Color Change made it the Psychic type!");
}
}
}
SINGLE_BATTLE_TEST("Color Change changes the user to Electric type if hit by a move while the opponent is under the effect of Electrify")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(opponent, MOVE_ELECTRIFY); MOVE(player, MOVE_PSYCHO_CUT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHO_CUT, player);
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("Foe Wobbuffet's Color Change made it the Electr type!");
}
}
SINGLE_BATTLE_TEST("Color Change changes the type when a Pokemon is hit by Future Sight")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SNORLAX) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(player, MOVE_FUTURE_SIGHT); }
TURN { }
TURN { }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
MESSAGE("Foe Snorlax took the Future Sight attack!");
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("Foe Snorlax's Color Change made it the Psychc type!");
}
}
SINGLE_BATTLE_TEST("Color Change changes the type when a Pokemon is hit by Doom Desire")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(player, MOVE_DOOM_DESIRE); }
TURN { }
TURN { }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOOM_DESIRE, player);
MESSAGE("Foe Wobbuffet took the Doom Desire attack!");
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("Foe Wobbuffet's Color Change made it the Steel type!");
}
}
SINGLE_BATTLE_TEST("Color Change changes the type to Electric when a Pokemon is hit by a forseen attack under the effect of Electrify")
{
KNOWN_FAILING; // #4471.
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_BLASTOISE) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_FUTURE_SIGHT); }
TURN { }
TURN { MOVE(opponent, MOVE_ELECTRIFY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
MESSAGE("Foe Blastoise took the Future Sight attack!");
MESSAGE("It's super effective!");
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("Foe Blastoise's Color Change made it the Electr type!");
}
}
SINGLE_BATTLE_TEST("Color Change changes the type to Normal when a Pokemon is hit by a forseen attack under the effect of Normalize")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_NORMALIZE); }
OPPONENT(SPECIES_BLASTOISE) { Ability(ABILITY_COLOR_CHANGE); }
} WHEN {
TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_FUTURE_SIGHT); }
TURN { }
TURN { }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
MESSAGE("Foe Blastoise took the Future Sight attack!");
ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE);
MESSAGE("Foe Blastoise's Color Change made it the Normal type!");
}
}

View file

@ -2,14 +2,14 @@
#include "test/battle.h"
SINGLE_BATTLE_TEST("Embodoy Aspect raises a stat depending on the users form by one stage")
SINGLE_BATTLE_TEST("Embody Aspect raises a stat depending on the users form by one stage")
{
u16 species, ability;
PARAMETRIZE { species = SPECIES_OGERPON_TEAL_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_TEAL; }
PARAMETRIZE { species = SPECIES_OGERPON_HEARTHFLAME_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_HEARTHFLAME; }
PARAMETRIZE { species = SPECIES_OGERPON_WELLSPRING_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_WELLSPRING; }
PARAMETRIZE { species = SPECIES_OGERPON_CORNERSTONE_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_CORNERSTONE; }
PARAMETRIZE { species = SPECIES_OGERPON_TEAL_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_TEAL_MASK; }
PARAMETRIZE { species = SPECIES_OGERPON_HEARTHFLAME_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK; }
PARAMETRIZE { species = SPECIES_OGERPON_WELLSPRING_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_WELLSPRING_MASK; }
PARAMETRIZE { species = SPECIES_OGERPON_CORNERSTONE_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
@ -19,32 +19,32 @@ SINGLE_BATTLE_TEST("Embodoy Aspect raises a stat depending on the users form by
} SCENE {
ABILITY_POPUP(opponent, ability);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
if (ability == ABILITY_EMBODY_ASPECT_TEAL)
MESSAGE("Foe Ogerpon's Embody Aspect raised its Sp. Atk!");
else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME)
if (ability == ABILITY_EMBODY_ASPECT_TEAL_MASK)
MESSAGE("Foe Ogerpon's Embody Aspect raised its Speed!");
else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK)
MESSAGE("Foe Ogerpon's Embody Aspect raised its Attack!");
else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING)
else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING_MASK)
MESSAGE("Foe Ogerpon's Embody Aspect raised its Sp. Def!");
else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE)
else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK)
MESSAGE("Foe Ogerpon's Embody Aspect raised its Defense!");
} THEN {
if (ability == ABILITY_EMBODY_ASPECT_TEAL)
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME)
if (ability == ABILITY_EMBODY_ASPECT_TEAL_MASK)
EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1);
else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK)
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING)
else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING_MASK)
EXPECT_EQ(opponent->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1);
else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE)
else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK)
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
}
}
SINGLE_BATTLE_TEST("Embodoy Aspect activates when it's no longer effected by Neutralizing Gas")
SINGLE_BATTLE_TEST("Embody Aspect activates when it's no longer effected by Neutralizing Gas")
{
GIVEN {
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_OGERPON_TEAL_MASK_TERA) { Ability(ABILITY_EMBODY_ASPECT_TEAL); }
OPPONENT(SPECIES_OGERPON_TEAL_MASK_TERA) { Ability(ABILITY_EMBODY_ASPECT_TEAL_MASK); }
} WHEN {
TURN { SWITCH(player, 1); }
} SCENE {
@ -52,8 +52,8 @@ SINGLE_BATTLE_TEST("Embodoy Aspect activates when it's no longer effected by Neu
MESSAGE("Neutralizing Gas filled the area!");
MESSAGE("Weezing, that's enough! Come back!");
MESSAGE("The effects of Neutralizing Gas wore off!");
ABILITY_POPUP(opponent, ABILITY_EMBODY_ASPECT_TEAL);
ABILITY_POPUP(opponent, ABILITY_EMBODY_ASPECT_TEAL_MASK);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Foe Ogerpon's Embody Aspect raised its Sp. Atk!");
MESSAGE("Foe Ogerpon's Embody Aspect raised its Speed!");
}
}

View file

@ -68,3 +68,24 @@ DOUBLE_BATTLE_TEST("Hospitality ignores Substitute")
MESSAGE("Wobbuffet drank down all the matcha that Poltchageist made!");
}
}
DOUBLE_BATTLE_TEST("Hospitality does not trigger if there is no ally on the field")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
PLAYER(SPECIES_POLTCHAGEIST) { Ability(ABILITY_HOSPITALITY); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_BLIZZARD); SEND_OUT(playerLeft, 2); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BLIZZARD, opponentLeft);
HP_BAR(playerLeft);
MESSAGE("Wobbuffet fainted!");
HP_BAR(playerRight);
MESSAGE("Wobbuffet fainted!");
MESSAGE("Go! Ptchageist!");
NOT ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY);
}
}

View file

@ -81,3 +81,54 @@ DOUBLE_BATTLE_TEST("Magic Bounce bounces back moves hitting both foes at two foe
MESSAGE("Foe Wynaut's Defense fell!");
}
}
DOUBLE_BATTLE_TEST("Magic Bounce bounces back moves hitting foes field")
{
u32 battlerOne, battlerTwo, abilityBattlerOne, abilityBattlerTwo;
PARAMETRIZE { battlerOne = SPECIES_NATU; abilityBattlerOne = ABILITY_MAGIC_BOUNCE;
battlerTwo = SPECIES_ESPEON; abilityBattlerTwo = ABILITY_SYNCHRONIZE; }
PARAMETRIZE { battlerOne = SPECIES_NATU; abilityBattlerOne = ABILITY_KEEN_EYE;
battlerTwo = SPECIES_ESPEON; abilityBattlerTwo = ABILITY_MAGIC_BOUNCE; }
GIVEN {
ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].target == MOVE_TARGET_OPPONENTS_FIELD);
PLAYER(SPECIES_ABRA);
PLAYER(SPECIES_KADABRA);
OPPONENT(battlerOne) { Ability(abilityBattlerOne); }
OPPONENT(battlerTwo) { Ability(abilityBattlerTwo); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_STEALTH_ROCK); }
} SCENE {
if (abilityBattlerOne == ABILITY_MAGIC_BOUNCE)
ABILITY_POPUP(opponentLeft, ABILITY_MAGIC_BOUNCE);
else
ABILITY_POPUP(opponentRight, ABILITY_MAGIC_BOUNCE);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, playerLeft);
if (abilityBattlerOne == ABILITY_MAGIC_BOUNCE) {
MESSAGE("Abra's Stealth Rock was bounced back by Foe Natu's Magic Bounce!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentLeft);
} else {
MESSAGE("Abra's Stealth Rock was bounced back by Foe Espeon's Magic Bounce!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentRight);
}
}
}
SINGLE_BATTLE_TEST("Magic Bounce bounced back status moves can not be bounced back by Magic Bounce")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
PLAYER(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); }
OPPONENT(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); }
} WHEN {
TURN { MOVE(player, MOVE_TOXIC); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_MAGIC_BOUNCE);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
MESSAGE("Espeon's Toxic was bounced back by Foe Espeon's Magic Bounce!");
NOT ABILITY_POPUP(player, ABILITY_MAGIC_BOUNCE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, opponent);
STATUS_ICON(player, badPoison: TRUE);
}
}

View file

@ -548,6 +548,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculati
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculation checks whether incoming damage is zero to avoid an infinite loop")
{
GIVEN {
ASSUME(gItemsInfo[ITEM_LEFTOVERS].holdEffect == HOLD_EFFECT_LEFTOVERS);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
PLAYER(SPECIES_BULBASAUR) { Level(5); Moves(MOVE_SWORDS_DANCE, MOVE_WHIRLWIND, MOVE_SAND_ATTACK, MOVE_TAIL_WHIP); }
// Scenario courtesy of Duke, who triggered the bug in the first place
@ -561,6 +562,23 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculati
}
}
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Avoid infinite loop if damage taken is equal to recurring healing")
{
GIVEN {
ASSUME(gItemsInfo[ITEM_LEFTOVERS].holdEffect == HOLD_EFFECT_LEFTOVERS);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
PLAYER(SPECIES_MEOWTH_GALARIAN) { Level(100); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); }
// Scenario courtesy of Duke, who triggered the bug in the first place
OPPONENT(SPECIES_MEOWTH_GALARIAN) { Level(5); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); }
OPPONENT(SPECIES_GEODUDE) { Level(5); Moves(MOVE_DOUBLE_EDGE); }
OPPONENT(SPECIES_GEODUDE) { Level(5); Moves(MOVE_DOUBLE_EDGE); }
OPPONENT(SPECIES_NOSEPASS) { Level(5); Moves(MOVE_DOUBLE_EDGE); }
OPPONENT(SPECIES_HOUNDSTONE) { Level(5); Moves(MOVE_NIGHT_SHADE, MOVE_BODY_PRESS, MOVE_WILL_O_WISP, MOVE_PROTECT); Item(ITEM_LEFTOVERS); }
} WHEN {
TURN { MOVE(player, MOVE_FAKE_OUT); EXPECT_MOVES(opponent, MOVE_FAKE_OUT); }
}
}
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will not switch in a Pokemon which is slower and gets 1HKOed after fainting")
{
bool32 alakazamFirst;

View file

@ -22,6 +22,7 @@ SINGLE_BATTLE_TEST("Eject Pack does not cause the new pokemon to lose hp due to
MESSAGE("Wobbuffet is switched out with the Eject Pack!");
MESSAGE("Go! Wynaut!");
NOT MESSAGE("Wynaut was hurt by its Life Orb!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent);
}
}
@ -41,3 +42,24 @@ SINGLE_BATTLE_TEST("Eject Pack does not activate if there are no pokemon left to
}
}
}
SINGLE_BATTLE_TEST("Eject Pack triggers on the correct pokemon")
{
GIVEN {
ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(player, MOVE_OVERHEAT); SEND_OUT(player, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_OVERHEAT, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Wobbuffet is switched out with the Eject Pack!");
MESSAGE("Go! Wynaut!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent);
}
}

View file

@ -30,3 +30,46 @@ SINGLE_BATTLE_TEST("Stealth Rock damage on switch in based on typing")
HP_BAR(opponent, damage: maxHP / divisor);
}
}
SINGLE_BATTLE_TEST("Stealth Rock damages the correct pokemon when Eject Button is triggered")
{
GIVEN {
PLAYER(SPECIES_METAPOD) { Item(ITEM_EJECT_BUTTON); }
PLAYER(SPECIES_METAPOD);
OPPONENT(SPECIES_JOLTEON);
} WHEN {
TURN { MOVE(opponent, MOVE_STEALTH_ROCK); MOVE(player, MOVE_HARDEN); }
TURN { MOVE(opponent, MOVE_QUICK_ATTACK); MOVE(player, MOVE_HARDEN); SEND_OUT(player, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_HARDEN, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponent);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HARDEN, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Go! Metapod!");
HP_BAR(player);
} THEN {
EXPECT_EQ(opponent->hp, opponent->maxHP);
}
}
DOUBLE_BATTLE_TEST("Stealth Rock damages the correct pokemon when Eject Button is triggered in double battle")
{
GIVEN {
PLAYER(SPECIES_METAPOD) { Item(ITEM_EJECT_BUTTON); }
PLAYER(SPECIES_METAPOD) { Item(ITEM_EJECT_BUTTON); }
PLAYER(SPECIES_METAPOD);
OPPONENT(SPECIES_JOLTEON);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_STEALTH_ROCK); MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); SEND_OUT(playerLeft, 2); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerLeft);
MESSAGE("Go! Metapod!");
HP_BAR(playerLeft);
} THEN {
EXPECT_EQ(opponentLeft->hp, opponentLeft->maxHP);
}
}